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