...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package debug
17
18 import (
19 "context"
20 "fmt"
21 "strconv"
22
23 "code.cloudfoundry.org/bytefmt"
24 "github.com/hasura/go-graphql-client"
25
26 "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common"
27 ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client"
28 )
29
30 type stressDebugger struct {
31 client *ctrlclient.CtrlClient
32 }
33
34 func StressDebug(client *ctrlclient.CtrlClient) Debugger {
35 return &stressDebugger{
36 client: client,
37 }
38 }
39
40 func (d *stressDebugger) Collect(ctx context.Context, namespace, chaosName string) ([]*common.ChaosResult, error) {
41 var results []*common.ChaosResult
42
43 var name *graphql.String
44 if chaosName != "" {
45 n := graphql.String(chaosName)
46 name = &n
47 }
48
49 var query struct {
50 Namespace []struct {
51 StressChaos []struct {
52 Name string
53 Podstress []struct {
54 Pod struct {
55 Namespace string
56 Name string
57 }
58 Cgroups struct {
59 Raw string
60 Cpu *struct {
61 Quota int
62 Period int
63 }
64 Memory *struct {
65 Limit uint64
66 }
67 }
68 ProcessStress []struct {
69 Process struct {
70 Pid string
71 Command string
72 }
73 Cgroup string
74 }
75 }
76 } `graphql:"stresschaos(name: $name)"`
77 } `graphql:"namespace(ns: $namespace)"`
78 }
79
80 variables := map[string]interface{}{
81 "namespace": graphql.String(namespace),
82 "name": name,
83 }
84
85 err := d.client.QueryClient.Query(ctx, &query, variables)
86 if err != nil {
87 return nil, err
88 }
89
90 if len(query.Namespace) == 0 {
91 return results, nil
92 }
93
94 for _, stressChaos := range query.Namespace[0].StressChaos {
95 result := &common.ChaosResult{
96 Name: stressChaos.Name,
97 }
98
99 for _, podStressChaos := range stressChaos.Podstress {
100 podResult := common.PodResult{
101 Name: podStressChaos.Pod.Name,
102 }
103
104 podResult.Items = append(podResult.Items, common.ItemResult{Name: "cat /proc/cgroups", Value: podStressChaos.Cgroups.Raw})
105 for _, process := range podStressChaos.ProcessStress {
106 podResult.Items = append(podResult.Items, common.ItemResult{
107 Name: fmt.Sprintf("/proc/%s/cgroup of %s", process.Process.Pid, process.Process.Command),
108 Value: process.Cgroup,
109 })
110 }
111 if podStressChaos.Cgroups.Cpu != nil {
112 podResult.Items = append(podResult.Items, common.ItemResult{Name: "cpu.cfs_quota_us", Value: strconv.Itoa(podStressChaos.Cgroups.Cpu.Quota)})
113 periodItem := common.ItemResult{Name: "cpu.cfs_period_us", Value: strconv.Itoa(podStressChaos.Cgroups.Cpu.Period)}
114 if podStressChaos.Cgroups.Cpu.Quota == -1 {
115 periodItem.Status = common.ItemFailure
116 periodItem.ErrInfo = "no cpu limit is set for now"
117 } else {
118 periodItem.Status = common.ItemSuccess
119 periodItem.SucInfo = fmt.Sprintf("cpu limit is equals to %.2f", float64(podStressChaos.Cgroups.Cpu.Quota)/float64(podStressChaos.Cgroups.Cpu.Period))
120 }
121 podResult.Items = append(podResult.Items, periodItem)
122 }
123
124 if podStressChaos.Cgroups.Memory != nil {
125 podResult.Items = append(podResult.Items, common.ItemResult{Name: "memory.limit_in_bytes", Value: bytefmt.ByteSize(podStressChaos.Cgroups.Memory.Limit) + "B"})
126 }
127 result.Pods = append(result.Pods, podResult)
128 }
129 results = append(results, result)
130 }
131 return results, nil
132 }
133
134 func (d *stressDebugger) List(ctx context.Context, namespace string) ([]string, error) {
135 var query struct {
136 Namespace []struct {
137 StressChaos []struct {
138 Name string
139 } `graphql:"stresschaos"`
140 } `graphql:"namespace(ns: $namespace)"`
141 }
142
143 variables := map[string]interface{}{
144 "namespace": graphql.String(namespace),
145 }
146
147 err := d.client.QueryClient.Query(ctx, &query, variables)
148 if err != nil {
149 return nil, err
150 }
151
152 if len(query.Namespace) == 0 {
153 return nil, nil
154 }
155
156 var names []string
157 for _, stressChaos := range query.Namespace[0].StressChaos {
158 names = append(names, string(stressChaos.Name))
159 }
160 return names, nil
161 }
162