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