1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package chaos
17
18 import (
19 "context"
20 "fmt"
21 "net/http"
22 "strconv"
23 "strings"
24 "time"
25
26 "github.com/onsi/ginkgo/v2"
27 "github.com/pkg/errors"
28 v1 "k8s.io/api/core/v1"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/labels"
31 "k8s.io/apimachinery/pkg/runtime"
32 "k8s.io/client-go/kubernetes"
33 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
34 restClient "k8s.io/client-go/rest"
35 "k8s.io/kubernetes/test/e2e/framework"
36 "k8s.io/pod-security-admission/api"
37 "sigs.k8s.io/controller-runtime/pkg/client"
38
39 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
40 dnschaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/dnschaos"
41 httpchaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/httpchaos"
42 iochaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/iochaos"
43 networkchaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/networkchaos"
44 podchaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/podchaos"
45 sidecartestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/sidecar"
46 stresstestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/stresschaos"
47 timechaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/timechaos"
48 e2econfig "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config"
49 "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/e2econst"
50 "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util"
51 "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture"
52 "github.com/chaos-mesh/chaos-mesh/pkg/log"
53 "github.com/chaos-mesh/chaos-mesh/pkg/portforward"
54 )
55
56 var _ = ginkgo.Describe("[Basic]", func() {
57 f := framework.NewDefaultFramework("chaos-mesh")
58 f.NamespacePodSecurityEnforceLevel = api.LevelPrivileged
59 var ns string
60 var fwCancel context.CancelFunc
61 var fw portforward.PortForward
62 var kubeCli kubernetes.Interface
63 var config *restClient.Config
64 var cli client.Client
65 c := http.Client{
66 Timeout: 10 * time.Second,
67 }
68
69 ginkgo.BeforeEach(func() {
70 ns = f.Namespace.Name
71 ctx, cancel := context.WithCancel(context.Background())
72 clientRawConfig, err := e2econfig.LoadClientRawConfig()
73 framework.ExpectNoError(err, "failed to load raw config")
74 logger, err := log.NewDefaultZapLogger()
75 framework.ExpectNoError(err, "failed to create logger")
76 fw, err = portforward.NewPortForwarder(ctx, e2econfig.NewSimpleRESTClientGetter(clientRawConfig), true, logger)
77 framework.ExpectNoError(err, "failed to create port forwarder")
78 fwCancel = cancel
79 kubeCli = f.ClientSet
80 config, err = framework.LoadConfig()
81 framework.ExpectNoError(err, "config error")
82 scheme := runtime.NewScheme()
83 _ = clientgoscheme.AddToScheme(scheme)
84 _ = v1alpha1.AddToScheme(scheme)
85 cli, err = client.New(config, client.Options{Scheme: scheme})
86 framework.ExpectNoError(err, "create client error")
87 })
88
89 ginkgo.AfterEach(func() {
90 if fwCancel != nil {
91 fwCancel()
92 }
93 })
94
95 ginkgo.Context("[PodChaos]", func() {
96 ginkgo.Context("[PodFailure]", func() {
97 ginkgo.It("[Schedule]", func() {
98 podchaostestcases.TestcasePodFailureOnceThenDelete(ns, kubeCli, cli)
99 })
100 ginkgo.It("[Pause]", func() {
101 podchaostestcases.TestcasePodFailurePauseThenUnPause(ns, kubeCli, cli)
102 })
103 })
104 ginkgo.Context("[PodKill]", func() {
105 ginkgo.It("[Schedule]", func() {
106 podchaostestcases.TestcasePodKillOnceThenDelete(ns, kubeCli, cli)
107 })
108 ginkgo.It("[Pause]", func() {
109 podchaostestcases.TestcasePodKillPauseThenUnPause(ns, kubeCli, cli)
110 })
111 })
112 ginkgo.Context("[ContainerKill]", func() {
113 ginkgo.It("[Schedule]", func() {
114 podchaostestcases.TestcaseContainerKillOnceThenDelete(ns, kubeCli, cli)
115 })
116 ginkgo.It("[Pause]", func() {
117 podchaostestcases.TestcaseContainerKillPauseThenUnPause(ns, kubeCli, cli)
118 })
119 })
120 })
121
122
123 ginkgo.Context("[TimeChaos]", func() {
124
125 var err error
126 var port uint16
127 var pfCancel context.CancelFunc
128
129 ginkgo.JustBeforeEach(func() {
130 svc := fixture.NewE2EService("timer", ns)
131 _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{})
132 framework.ExpectNoError(err, "create service error")
133 nd := fixture.NewTimerDeployment("timer", ns)
134 _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{})
135 framework.ExpectNoError(err, "create timer deployment error")
136 err = util.WaitDeploymentReady("timer", ns, kubeCli)
137 framework.ExpectNoError(err, "wait timer deployment ready error")
138 _, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/timer", 8080)
139 framework.ExpectNoError(err, "create helper port-forward failed")
140 })
141
142 ginkgo.JustAfterEach(func() {
143 if pfCancel != nil {
144 pfCancel()
145 }
146 })
147
148
149 ginkgo.Context("[TimeSkew]", func() {
150
151 ginkgo.It("[Schedule]", func() {
152 timechaostestcases.TestcaseTimeSkewOnceThenRecover(ns, cli, c, port)
153 })
154
155 ginkgo.It("[Pause]", func() {
156 timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port)
157 })
158
159 ginkgo.It("[Child Process]", func() {
160 timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port)
161 })
162 })
163 })
164
165
166 ginkgo.Context("[IOChaos]", func() {
167
168 var (
169 err error
170 port uint16
171 pfCancel context.CancelFunc
172 )
173
174 ginkgo.JustBeforeEach(func() {
175 svc := fixture.NewE2EService("io", ns)
176 _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{})
177 framework.ExpectNoError(err, "create service error")
178 nd := fixture.NewIOTestDeployment("io-test", ns)
179 _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{})
180 framework.ExpectNoError(err, "create io-test deployment error")
181 err = util.WaitDeploymentReady("io-test", ns, kubeCli)
182 framework.ExpectNoError(err, "wait io-test deployment ready error")
183 _, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/io", 8080)
184 framework.ExpectNoError(err, "create helper io port port-forward failed")
185 })
186
187 ginkgo.JustAfterEach(func() {
188 if pfCancel != nil {
189 pfCancel()
190 }
191 })
192
193
194 ginkgo.Context("[IODelay]", func() {
195
196 ginkgo.It("[Schedule]", func() {
197 iochaostestcases.TestcaseIODelayDurationForATimeThenRecover(ns, cli, c, port)
198 })
199
200 ginkgo.It("[Pause]", func() {
201 iochaostestcases.TestcaseIODelayDurationForATimePauseAndUnPause(ns, cli, c, port)
202 })
203 ginkgo.It("[SpecifyContainer]", func() {
204 iochaostestcases.TestcaseIODelayWithSpecifiedContainer(ns, cli, c, port)
205 })
206 ginkgo.It("[WrongSpec]", func() {
207 iochaostestcases.TestcaseIODelayWithWrongSpec(ns, cli, c, port)
208 })
209 })
210
211
212 ginkgo.Context("[IOErrno]", func() {
213
214 ginkgo.It("[Schedule]", func() {
215 iochaostestcases.TestcaseIOErrorDurationForATimeThenRecover(ns, cli, c, port)
216 })
217 ginkgo.It("[Pause]", func() {
218 iochaostestcases.TestcaseIOErrorDurationForATimePauseAndUnPause(ns, cli, c, port)
219 })
220 ginkgo.It("[SpecifyContainer]", func() {
221 iochaostestcases.TestcaseIOErrorWithSpecifiedContainer(ns, cli, c, port)
222 })
223 })
224
225
226 ginkgo.Context("[IOMistake]", func() {
227
228 ginkgo.It("[Schedule]", func() {
229 iochaostestcases.TestcaseIOMistakeDurationForATimeThenRecover(ns, cli, c, port)
230 })
231 ginkgo.It("[Pause]", func() {
232 iochaostestcases.TestcaseIOMistakeDurationForATimePauseAndUnPause(ns, cli, c, port)
233 })
234 ginkgo.It("[SpecifyContainer]", func() {
235 iochaostestcases.TestcaseIOMistakeWithSpecifiedContainer(ns, cli, c, port)
236 })
237 })
238 })
239
240
241 ginkgo.Context("[HTTPChaos]", func() {
242 var (
243 err error
244 port uint16
245 tlsPort uint16
246 pfCancel context.CancelFunc
247 client httpchaostestcases.HTTPE2EClient
248 )
249
250 ginkgo.JustBeforeEach(func() {
251 svc := fixture.NewE2EService("http", ns)
252 svc, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{})
253 framework.ExpectNoError(err, "create service error")
254 for _, servicePort := range svc.Spec.Ports {
255 if servicePort.Name == "http" {
256 port = uint16(servicePort.NodePort)
257 continue
258 }
259 if servicePort.Name == "https" {
260 tlsPort = uint16(servicePort.NodePort)
261 continue
262 }
263 }
264 nd := fixture.NewHTTPTestDeployment("http-test", ns)
265 _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{})
266 framework.ExpectNoError(err, "create http-test deployment error")
267 err = util.WaitDeploymentReady("http-test", ns, kubeCli)
268 framework.ExpectNoError(err, "wait http-test deployment ready error")
269 podlist, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{})
270 framework.ExpectNoError(err, "find pod list error")
271 for _, item := range podlist.Items {
272 if strings.Contains(item.Name, "http-test") {
273 framework.Logf("get http-test-pod %v", item)
274 client.IP = item.Status.HostIP
275 break
276 }
277 }
278 client.C = &c
279 })
280
281 ginkgo.JustAfterEach(func() {
282 if pfCancel != nil {
283 pfCancel()
284 }
285 })
286
287
288 ginkgo.Context("[HTTPDelay]", func() {
289 ginkgo.It("[Schedule]", func() {
290 httpchaostestcases.TestcaseHttpDelayDurationForATimeThenRecover(ns, cli, client, port)
291 })
292 ginkgo.It("[Pause]", func() {
293 httpchaostestcases.TestcaseHttpDelayDurationForATimePauseAndUnPause(ns, cli, client, port)
294 })
295 })
296
297
298 ginkgo.Context("[HTTPAbort]", func() {
299 ginkgo.It("[Schedule]", func() {
300 httpchaostestcases.TestcaseHttpAbortThenRecover(ns, cli, client, port)
301 })
302 ginkgo.It("[Pause]", func() {
303 httpchaostestcases.TestcaseHttpAbortPauseAndUnPause(ns, cli, client, port)
304 })
305 })
306
307
308 ginkgo.Context("[HTTPReplace]", func() {
309 ginkgo.It("[Schedule]", func() {
310 httpchaostestcases.TestcaseHttpReplaceThenRecover(ns, cli, client, port)
311 })
312 ginkgo.It("[Pause]", func() {
313 httpchaostestcases.TestcaseHttpReplacePauseAndUnPause(ns, cli, client, port)
314 })
315 })
316
317
318 ginkgo.Context("[HTTPReplaceBody]", func() {
319 ginkgo.It("[Schedule]", func() {
320 httpchaostestcases.TestcaseHttpReplaceBodyThenRecover(ns, cli, client, port)
321 })
322 ginkgo.It("[Pause]", func() {
323 httpchaostestcases.TestcaseHttpReplaceBodyPauseAndUnPause(ns, cli, client, port)
324 })
325 })
326
327
328 ginkgo.Context("[HTTPPatch]", func() {
329 ginkgo.It("[Schedule]", func() {
330 httpchaostestcases.TestcaseHttpPatchThenRecover(ns, cli, client, port)
331 })
332 ginkgo.It("[Pause]", func() {
333 httpchaostestcases.TestcaseHttpPatchPauseAndUnPause(ns, cli, client, port)
334 })
335 })
336
337
338 ginkgo.Context("[HTTP TLS]", func() {
339 ginkgo.It("[Schedule]", func() {
340 httpchaostestcases.TestcaseHttpTLSThenRecover(ns, kubeCli, cli, client, port, tlsPort)
341 })
342 })
343 })
344
345 ginkgo.Context("[Sidecar Config]", func() {
346 var (
347 cmName string
348 cmNamespace string
349 )
350
351
352 ginkgo.JustAfterEach(func() {
353 kubeCli.CoreV1().ConfigMaps(cmNamespace).Delete(context.TODO(), cmName, metav1.DeleteOptions{})
354 })
355
356 ginkgo.Context("[Template Config]", func() {
357
358 ginkgo.It("[InValid ConfigMap key]", func() {
359 cmName = "incorrect-key-name"
360 cmNamespace = e2econst.ChaosMeshNamespace
361 sidecartestcases.TestcaseInvalidConfigMapKey(ns, cmNamespace, cmName, kubeCli, cli)
362 })
363
364 ginkgo.It("[InValid Configuration]", func() {
365 cmName = "incorrect-configuration"
366 cmNamespace = e2econst.ChaosMeshNamespace
367 sidecartestcases.TestcaseInvalidConfiguration(ns, cmNamespace, cmName, kubeCli, cli)
368 })
369 })
370
371 ginkgo.Context("[Injection Config]", func() {
372 ginkgo.It("[No Template]", func() {
373 cmName = "no-template-name"
374 cmNamespace = e2econst.ChaosMeshNamespace
375 sidecartestcases.TestcaseNoTemplate(ns, cmNamespace, cmName, kubeCli, cli)
376 })
377
378 ginkgo.It("[No Template Args]", func() {
379 cmName = "no-template-args"
380 cmNamespace = e2econst.ChaosMeshNamespace
381 sidecartestcases.TestcaseNoTemplateArgs(ns, cmNamespace, cmName, kubeCli, cli)
382 })
383 })
384 })
385
386 ginkgo.Context("[NetworkChaos]", func() {
387 var err error
388
389 var networkPeers []*v1.Pod
390 var ports []uint16
391 var pfCancels []context.CancelFunc
392
393 ginkgo.JustBeforeEach(func() {
394 ports = []uint16{}
395 networkPeers = []*v1.Pod{}
396 for index := 0; index < 4; index++ {
397 name := fmt.Sprintf("network-peer-%d", index)
398
399 svc := fixture.NewE2EService(name, ns)
400 _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{})
401 framework.ExpectNoError(err, "create service error")
402 nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": strconv.Itoa(index % 2)})
403 _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{})
404 framework.ExpectNoError(err, "create network-peer deployment error")
405 err = util.WaitDeploymentReady(name, ns, kubeCli)
406 framework.ExpectNoError(err, "wait network-peer deployment ready error")
407
408 pod, err := getPod(kubeCli, ns, name)
409 framework.ExpectNoError(err, "select network-peer pod error")
410 networkPeers = append(networkPeers, pod)
411
412 _, port, pfCancel, err := portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080)
413 ports = append(ports, port)
414 pfCancels = append(pfCancels, pfCancel)
415 framework.ExpectNoError(err, "create helper io port port-forward failed")
416 }
417 })
418
419 ginkgo.Context("[ForbidHostNetwork]", func() {
420 ginkgo.It("[Schedule]", func() {
421 networkchaostestcases.TestcaseForbidHostNetwork(ns, kubeCli, cli)
422 })
423 })
424
425 ginkgo.Context("[NetworkPartition]", func() {
426 ginkgo.It("[Schedule]", func() {
427 networkchaostestcases.TestcaseNetworkPartition(ns, cli, networkPeers, ports, c)
428 })
429 })
430
431 ginkgo.Context("[Netem]", func() {
432 ginkgo.It("[Schedule]", func() {
433 networkchaostestcases.TestcaseNetworkDelay(ns, cli, networkPeers, ports, c)
434 })
435 ginkgo.It("[PeersCrossoverWithDirectionBoth]", func() {
436 networkchaostestcases.TestcasePeersCrossover(ns, cli, networkPeers, ports, c)
437 })
438 })
439
440 ginkgo.JustAfterEach(func() {
441 for _, cancel := range pfCancels {
442 cancel()
443 }
444 })
445 })
446
447 ginkgo.Context("[DNSChaos]", func() {
448 var err error
449 var port uint16
450
451 ginkgo.JustBeforeEach(func() {
452 name := "network-peer"
453
454 svc := fixture.NewE2EService(name, ns)
455 _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{})
456 framework.ExpectNoError(err, "create service error")
457 nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": "0"})
458 _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{})
459 framework.ExpectNoError(err, "create network-peer deployment error")
460 err = util.WaitDeploymentReady(name, ns, kubeCli)
461 framework.ExpectNoError(err, "wait network-peer deployment ready error")
462
463 _, err = getPod(kubeCli, ns, name)
464 framework.ExpectNoError(err, "select network-peer pod error")
465
466 _, port, _, err = portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080)
467 framework.ExpectNoError(err, "create helper io port port-forward failed")
468 })
469 ginkgo.It("[RANDOM]", func() {
470 dnschaostestcases.TestcaseDNSRandom(ns, cli, port, c)
471 })
472
473 ginkgo.It("[ERROR]", func() {
474 dnschaostestcases.TestcaseDNSError(ns, cli, port, c)
475 })
476 })
477
478 ginkgo.Context("[StressChaos]", func() {
479 var err error
480
481 var ports []uint16
482 var stressPeers []*v1.Pod
483 var pfCancels []context.CancelFunc
484
485 ginkgo.JustBeforeEach(func() {
486 ports = []uint16{}
487 stressPeers = []*v1.Pod{}
488 for index := 0; index < 2; index++ {
489 name := fmt.Sprintf("stress-peer-%d", index)
490
491 svc := fixture.NewE2EService(name, ns)
492 _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{})
493 framework.ExpectNoError(err, "create service error")
494 nd := fixture.NewStressTestDeployment(name, ns, map[string]string{"partition": strconv.Itoa(index % 2)})
495 _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{})
496 framework.ExpectNoError(err, "create network-peer deployment error")
497 err = util.WaitDeploymentReady(name, ns, kubeCli)
498 framework.ExpectNoError(err, "wait network-peer deployment ready error")
499
500 pod, err := getPod(kubeCli, ns, name)
501 framework.ExpectNoError(err, "select network-peer pod error")
502 stressPeers = append(stressPeers, pod)
503
504 _, port, pfCancel, err := portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080)
505 ports = append(ports, port)
506 pfCancels = append(pfCancels, pfCancel)
507 framework.ExpectNoError(err, "create helper io port port-forward failed")
508 }
509 })
510
511 ginkgo.It("[CPU]", func() {
512 stresstestcases.TestcaseCPUStressInjectionOnceThenRecover(ns, cli, stressPeers, ports, c)
513 })
514
515
516 ginkgo.It("[Memory]", func() {
517 stresstestcases.TestcaseMemoryStressInjectionOnceThenRecover(ns, cli, stressPeers, ports, c)
518 })
519
520 ginkgo.JustAfterEach(func() {
521 for _, cancel := range pfCancels {
522 cancel()
523 }
524 })
525 })
526 })
527
528 func getPod(kubeCli kubernetes.Interface, ns string, appLabel string) (*v1.Pod, error) {
529 listOption := metav1.ListOptions{
530 LabelSelector: labels.SelectorFromSet(map[string]string{
531 "app": appLabel,
532 }).String(),
533 }
534
535 pods, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption)
536 if err != nil {
537 return nil, err
538 }
539
540 if len(pods.Items) > 1 {
541 return nil, errors.New("select more than one pod")
542 }
543
544 if len(pods.Items) == 0 {
545 return nil, errors.New("cannot select any pod")
546 }
547
548 return &pods.Items[0], nil
549 }
550