1
2
3
4
5
6
7
8
9
10
11
12
13
14 package stresschaos
15
16 import (
17 "context"
18 "fmt"
19 "regexp"
20 "strconv"
21 "strings"
22
23 "code.cloudfoundry.org/bytefmt"
24 "github.com/pkg/errors"
25 v1 "k8s.io/api/core/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27
28 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
29 cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common"
30 )
31
32
33 func Debug(ctx context.Context, chaos runtime.Object, c *cm.ClientSet, result *cm.ChaosResult) error {
34 stressChaos, ok := chaos.(*v1alpha1.StressChaos)
35 if !ok {
36 return fmt.Errorf("chaos is not stresschaos")
37 }
38 chaosStatus := stressChaos.Status.ChaosStatus
39 chaosSelector := stressChaos.Spec.Selector
40
41 pods, daemons, err := cm.GetPods(ctx, stressChaos.GetName(), chaosStatus, chaosSelector, c.CtrlCli)
42 if err != nil {
43 return err
44 }
45
46 for i := range pods {
47 podName := pods[i].Name
48 podResult := cm.PodResult{Name: podName}
49 _ = debugEachPod(ctx, pods[i], daemons[i], stressChaos, c, &podResult)
50 result.Pods = append(result.Pods, podResult)
51
52 }
53 return nil
54 }
55
56 func debugEachPod(ctx context.Context, pod v1.Pod, daemon v1.Pod, chaos *v1alpha1.StressChaos, c *cm.ClientSet, result *cm.PodResult) error {
57
58 cmd := "cat /proc/cgroups"
59 out, err := cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli)
60 if err != nil {
61 return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
62 }
63 result.Items = append(result.Items, cm.ItemResult{Name: "cat /proc/cgroups", Value: string(out)})
64
65 cmd = "ps"
66 out, err = cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli)
67 if err != nil {
68 return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
69 }
70 result.Items = append(result.Items, cm.ItemResult{Name: "ps", Value: string(out)})
71 stressngLine := regexp.MustCompile("(.*)(stress-ng)").FindStringSubmatch(string(out))
72 if len(stressngLine) == 0 {
73 return fmt.Errorf("could not find stress-ng, StressChaos failed")
74 }
75
76 pids, commands, err := cm.GetPidFromPS(ctx, pod, daemon, c.KubeCli)
77 if err != nil {
78 return errors.Wrap(err, "get pid from ps failed")
79 }
80
81 for i := range pids {
82 cmd = fmt.Sprintf("cat /proc/%s/cgroup", pids[i])
83 out, err = cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli)
84 if err != nil {
85 cm.L().WithName("stress-chaos").V(2).Info("failed to fetch cgroup ofr certain process",
86 "pod", fmt.Sprintf("%s/%s", pod.Namespace, pod.Name),
87 "pid", i,
88 )
89 result.Items = append(result.Items, cm.ItemResult{Name: fmt.Sprintf("/proc/%s/cgroup of %s", pids[i], commands[i]), Value: "No cgroup found"})
90 } else {
91 result.Items = append(result.Items, cm.ItemResult{Name: fmt.Sprintf("/proc/%s/cgroup of %s", pids[i], commands[i]), Value: string(out)})
92 }
93 }
94
95
96 if chaos.Spec.StressngStressors != "" {
97 return nil
98 }
99
100 isCPU := true
101 if cpuSpec := chaos.Spec.Stressors.CPUStressor; cpuSpec == nil {
102 isCPU = false
103 }
104
105 var expr, cpuMountType string
106 if isCPU {
107 if regexp.MustCompile("(cpu,cpuacct)").MatchString(string(out)) {
108 cpuMountType = "cpu,cpuacct"
109 } else {
110 cpuMountType = "cpu"
111 }
112 expr = "(?::" + cpuMountType + ":)(.*)"
113 } else {
114 expr = "(?::memory:)(.*)"
115 }
116 processPath := regexp.MustCompile(expr).FindStringSubmatch(string(out))[1]
117
118
119 if isCPU {
120 cmd = fmt.Sprintf("cat /sys/fs/cgroup/%s/%s/cpu.cfs_quota_us", cpuMountType, processPath)
121 out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
122 if err != nil {
123 return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
124 }
125 result.Items = append(result.Items, cm.ItemResult{Name: "cpu.cfs_quota_us", Value: string(out)})
126 quota, err := strconv.Atoi(strings.TrimSuffix(string(out), "\n"))
127 if err != nil {
128 return errors.Wrap(err, "could not get cpu.cfs_quota_us")
129 }
130
131 cmd = fmt.Sprintf("cat /sys/fs/cgroup/%s/%s/cpu.cfs_period_us", cpuMountType, processPath)
132 out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
133 if err != nil {
134 return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
135 }
136 period, err := strconv.Atoi(strings.TrimSuffix(string(out), "\n"))
137 if err != nil {
138 return errors.Wrap(err, "could not get cpu.cfs_period_us")
139 }
140 itemResult := cm.ItemResult{Name: "cpu.cfs_period_us", Value: string(out)}
141
142 if quota == -1 {
143 itemResult.Status = cm.ItemFailure
144 itemResult.ErrInfo = "no cpu limit is set for now"
145 } else {
146 itemResult.Status = cm.ItemSuccess
147 itemResult.SucInfo = fmt.Sprintf("cpu limit is equals to %.2f", float64(quota)/float64(period))
148 }
149 result.Items = append(result.Items, itemResult)
150 } else {
151 cmd = fmt.Sprintf("cat /sys/fs/cgroup/memory/%s/memory.limit_in_bytes", processPath)
152 out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
153 if err != nil {
154 return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
155 }
156 limit, err := strconv.ParseUint(strings.TrimSuffix(string(out), "\n"), 10, 64)
157 if err != nil {
158 return errors.Wrap(err, "could not get memory.limit_in_bytes")
159 }
160 result.Items = append(result.Items, cm.ItemResult{Name: "memory.limit_in_bytes", Value: bytefmt.ByteSize(limit) + "B"})
161 }
162 return nil
163 }
164