1
2
3
4
5
6
7
8
9
10
11
12
13
14 package networkchaos
15
16 import (
17 "context"
18 "fmt"
19 "io/ioutil"
20 "regexp"
21 "strconv"
22 "strings"
23
24 "github.com/pkg/errors"
25 "google.golang.org/grpc/grpclog"
26 v1 "k8s.io/api/core/v1"
27 "k8s.io/apimachinery/pkg/runtime"
28 "sigs.k8s.io/controller-runtime/pkg/client"
29
30 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
31 cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common"
32 )
33
34
35 func Debug(ctx context.Context, chaos runtime.Object, c *cm.ClientSet, result *cm.ChaosResult) error {
36 networkChaos, ok := chaos.(*v1alpha1.NetworkChaos)
37 if !ok {
38 return fmt.Errorf("chaos is not network")
39 }
40 chaosStatus := networkChaos.Status.ChaosStatus
41 chaosSelector := networkChaos.Spec.Selector
42
43 pods, daemons, err := cm.GetPods(ctx, networkChaos.GetName(), chaosStatus, chaosSelector, c.CtrlCli)
44 if err != nil {
45 return err
46 }
47
48 for i := range pods {
49 podName := pods[i].Name
50 podResult := cm.PodResult{Name: podName}
51 err = debugEachPod(ctx, pods[i], daemons[i], networkChaos, c, &podResult)
52 if err != nil {
53 fmt.Println(err)
54 }
55 result.Pods = append(result.Pods, podResult)
56
57 }
58 return nil
59 }
60
61 func debugEachPod(ctx context.Context, pod v1.Pod, daemon v1.Pod, chaos *v1alpha1.NetworkChaos, c *cm.ClientSet, result *cm.PodResult) error {
62
63
64 grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard))
65 pid, err := cm.GetPidFromPod(ctx, pod, daemon)
66 if err != nil {
67 return err
68 }
69 nsenterPath := fmt.Sprintf("-n/proc/%d/ns/net", pid)
70
71
72 cmd := fmt.Sprintf("/usr/bin/nsenter %s -- ipset list", nsenterPath)
73 out, err := cm.Exec(ctx, daemon, cmd, c.KubeCli)
74 if err != nil {
75 return errors.Wrap(err, fmt.Sprintf("run command '%s' failed", cmd))
76 }
77 result.Items = append(result.Items, cm.ItemResult{Name: "ipset list", Value: string(out)})
78
79 cmd = fmt.Sprintf("/usr/bin/nsenter %s -- tc qdisc list", nsenterPath)
80 out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
81 if err != nil {
82 return errors.Wrap(err, fmt.Sprintf("run command '%s' failed", cmd))
83 }
84 itemResult := cm.ItemResult{Name: "tc qdisc list", Value: string(out)}
85
86
87 action := chaos.Spec.Action
88 var netemExpect string
89 switch action {
90 case "delay":
91 latency := chaos.Spec.Delay.Latency
92 jitter := chaos.Spec.Delay.Jitter
93 correlation := chaos.Spec.Delay.Correlation
94 netemExpect = fmt.Sprintf("%v %v %v %v%%", action, latency, jitter, correlation)
95
96 netemCurrent := regexp.MustCompile("(?:limit 1000)(.*)").FindStringSubmatch(string(out))
97 if len(netemCurrent) == 0 {
98 return fmt.Errorf("no NetworkChaos is applied")
99 }
100 for i, netem := range strings.Fields(netemCurrent[1]) {
101 itemCurrent := netem
102 itemExpect := strings.Fields(netemExpect)[i]
103 if itemCurrent != itemExpect {
104 r := regexp.MustCompile("([0-9]*[.])?[0-9]+")
105
106 numCurrent, err := strconv.ParseFloat(r.FindString(itemCurrent), 64)
107 if err != nil {
108 return errors.Wrap(err, "parse itemCurrent failed")
109 }
110 numExpect, err := strconv.ParseFloat(r.FindString(itemExpect), 64)
111 if err != nil {
112 return errors.Wrap(err, "parse itemExpect failed")
113 }
114 if numCurrent == numExpect {
115 continue
116 }
117
118 alpCurrent := regexp.MustCompile("[[:alpha:]]+").FindString(itemCurrent)
119 alpExpect := regexp.MustCompile("[[:alpha:]]+").FindString(itemExpect)
120 if alpCurrent == alpExpect {
121 continue
122 }
123 itemResult.Status = cm.ItemFailure
124 itemResult.ErrInfo = fmt.Sprintf("expect: %s, got: %v", netemExpect, netemCurrent)
125 }
126 }
127 if itemResult.Status != cm.ItemFailure {
128 itemResult.Status = cm.ItemSuccess
129 }
130 }
131 result.Items = append(result.Items, itemResult)
132
133 cmd = fmt.Sprintf("/usr/bin/nsenter %s -- iptables --list", nsenterPath)
134 out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
135 if err != nil {
136 return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
137 }
138 result.Items = append(result.Items, cm.ItemResult{Name: "iptables list", Value: string(out)})
139
140 podNetworkChaos := &v1alpha1.PodNetworkChaos{}
141 objectKey := client.ObjectKey{
142 Namespace: pod.Namespace,
143 Name: pod.Name,
144 }
145
146 if err = c.CtrlCli.Get(ctx, objectKey, podNetworkChaos); err != nil {
147 return errors.Wrap(err, fmt.Sprintf("failed to get network chaos %s/%s", podNetworkChaos.GetNamespace(), podNetworkChaos.GetName()))
148 }
149 output, err := cm.MarshalChaos(podNetworkChaos.Spec)
150 if err != nil {
151 return err
152 }
153 result.Items = append(result.Items, cm.ItemResult{Name: "podnetworkchaos", Value: output})
154
155 return nil
156 }
157