1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package cmd
17
18 import (
19 "context"
20 "fmt"
21 "strings"
22
23 "github.com/go-logr/logr"
24 "github.com/spf13/cobra"
25 v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/client-go/kubernetes"
27 "sigs.k8s.io/controller-runtime/pkg/client"
28
29 "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common"
30 "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/iochaos"
31 "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/networkchaos"
32 "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/stresschaos"
33 "github.com/chaos-mesh/chaos-mesh/pkg/grpc"
34 )
35
36 type DebugOptions struct {
37 logger logr.Logger
38 namespace string
39 CaCertFile string
40 CertFile string
41 KeyFile string
42 Insecure bool
43 }
44
45 const (
46 networkChaos = "networkchaos"
47 stressChaos = "stresschaos"
48 ioChaos = "iochaos"
49 )
50
51 func NewDebugCommand(logger logr.Logger) (*cobra.Command, error) {
52 o := &DebugOptions{
53 logger: logger,
54 }
55
56 debugCmd := &cobra.Command{
57 Use: `debug (CHAOSTYPE) [-c CHAOSNAME] [-n NAMESPACE]`,
58 Short: `Print the debug information for certain chaos`,
59 Long: `Print the debug information for certain chaos.
60 Currently support networkchaos, stresschaos and iochaos.
61
62 Examples:
63 # Return debug information from all networkchaos in default namespace
64 chaosctl debug networkchaos
65
66 # Return debug information from certain networkchaos
67 chaosctl debug networkchaos CHAOSNAME -n NAMESPACE`,
68 ValidArgsFunction: noCompletions,
69 }
70
71
72 networkCmd := &cobra.Command{
73 Use: `networkchaos (CHAOSNAME) [-n NAMESPACE]`,
74 Short: `Print the debug information for certain network chaos`,
75 Long: `Print the debug information for certain network chaos`,
76 RunE: func(cmd *cobra.Command, args []string) error {
77 clientset, err := common.InitClientSet()
78 if err != nil {
79 return err
80 }
81 return o.Run(networkChaos, args, clientset)
82 },
83 SilenceErrors: true,
84 SilenceUsage: true,
85 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
86 clientset, err := common.InitClientSet()
87 if err != nil {
88 return nil, cobra.ShellCompDirectiveDefault
89 }
90 if len(args) != 0 {
91 return nil, cobra.ShellCompDirectiveNoFileComp
92 }
93 return listChaos(networkChaos, o.namespace, toComplete, clientset.CtrlCli)
94 },
95 }
96
97 stressCmd := &cobra.Command{
98 Use: `stresschaos (CHAOSNAME) [-n NAMESPACE]`,
99 Short: `Print the debug information for certain stress chaos`,
100 Long: `Print the debug information for certain stress chaos`,
101 RunE: func(cmd *cobra.Command, args []string) error {
102 clientset, err := common.InitClientSet()
103 if err != nil {
104 return err
105 }
106 return o.Run(stressChaos, args, clientset)
107 },
108 SilenceErrors: true,
109 SilenceUsage: true,
110 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
111 clientset, err := common.InitClientSet()
112 if err != nil {
113 return nil, cobra.ShellCompDirectiveDefault
114 }
115 if len(args) != 0 {
116 return nil, cobra.ShellCompDirectiveNoFileComp
117 }
118 return listChaos(stressChaos, o.namespace, toComplete, clientset.CtrlCli)
119 },
120 }
121
122 ioCmd := &cobra.Command{
123 Use: `iochaos (CHAOSNAME) [-n NAMESPACE]`,
124 Short: `Print the debug information for certain io chaos`,
125 Long: `Print the debug information for certain io chaos`,
126 RunE: func(cmd *cobra.Command, args []string) error {
127 clientset, err := common.InitClientSet()
128 if err != nil {
129 return err
130 }
131 return o.Run(ioChaos, args, clientset)
132
133 },
134 SilenceErrors: true,
135 SilenceUsage: true,
136 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
137 clientset, err := common.InitClientSet()
138 if err != nil {
139 return nil, cobra.ShellCompDirectiveDefault
140 }
141 if len(args) != 0 {
142 return nil, cobra.ShellCompDirectiveNoFileComp
143 }
144 return listChaos(ioChaos, o.namespace, toComplete, clientset.CtrlCli)
145 },
146 }
147
148 debugCmd.AddCommand(networkCmd)
149 debugCmd.AddCommand(stressCmd)
150 debugCmd.AddCommand(ioCmd)
151
152 debugCmd.PersistentFlags().StringVarP(&o.namespace, "namespace", "n", "default", "namespace to find chaos")
153 debugCmd.PersistentFlags().StringVar(&o.CaCertFile, "cacert", "", "file path to cacert file")
154 debugCmd.PersistentFlags().StringVar(&o.CertFile, "cert", "", "file path to cert file")
155 debugCmd.PersistentFlags().StringVar(&o.KeyFile, "key", "", "file path to key file")
156 debugCmd.PersistentFlags().BoolVarP(&o.Insecure, "insecure", "i", false, "Insecure mode will use unauthorized grpc")
157 err := debugCmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
158 clientset, err := common.InitClientSet()
159 if err != nil {
160 return nil, cobra.ShellCompDirectiveDefault
161 }
162 return listNamespace(toComplete, clientset.KubeCli)
163 })
164 return debugCmd, err
165 }
166
167
168 func (o *DebugOptions) Run(chaosType string, args []string, c *common.ClientSet) error {
169 if len(args) > 1 {
170 return fmt.Errorf("only one chaos could be specified")
171 }
172 ctx, cancel := context.WithCancel(context.Background())
173 defer cancel()
174
175 chaosName := ""
176 if len(args) == 1 {
177 chaosName = args[0]
178 }
179
180 chaosList, chaosNameList, err := common.GetChaosList(ctx, chaosType, chaosName, o.namespace, c.CtrlCli)
181 if err != nil {
182 return err
183 }
184 var result []common.ChaosResult
185 common.TLSFiles = grpc.TLSFile{CaCert: o.CaCertFile, Cert: o.CertFile, Key: o.KeyFile}
186 common.Insecure = o.Insecure
187
188 for i, chaos := range chaosList {
189 var chaosResult common.ChaosResult
190 chaosResult.Name = chaosNameList[i]
191
192 var err error
193 switch chaosType {
194 case networkChaos:
195 err = networkchaos.Debug(ctx, chaos, c, &chaosResult)
196 case stressChaos:
197 err = stresschaos.Debug(ctx, chaos, c, &chaosResult)
198 case ioChaos:
199 err = iochaos.Debug(ctx, chaos, c, &chaosResult)
200 default:
201 return fmt.Errorf("chaos type not supported")
202 }
203 result = append(result, chaosResult)
204 if err != nil {
205 common.PrintResult(result)
206 return err
207 }
208 }
209 common.PrintResult(result)
210 return nil
211 }
212
213 func listNamespace(toComplete string, c *kubernetes.Clientset) ([]string, cobra.ShellCompDirective) {
214
215 namespaces, err := c.CoreV1().Namespaces().List(context.TODO(), v1.ListOptions{})
216 if err != nil {
217 return nil, cobra.ShellCompDirectiveDefault
218 }
219 var ret []string
220 for _, ns := range namespaces.Items {
221 if strings.HasPrefix(ns.Name, toComplete) {
222 ret = append(ret, ns.Name)
223 }
224 }
225 return ret, cobra.ShellCompDirectiveNoFileComp
226 }
227
228 func listChaos(chaosType string, namespace string, toComplete string, c client.Client) ([]string, cobra.ShellCompDirective) {
229 ctx, cancel := context.WithCancel(context.Background())
230 defer cancel()
231 _, chaosList, err := common.GetChaosList(ctx, chaosType, "", namespace, c)
232 if err != nil {
233 return nil, cobra.ShellCompDirectiveDefault
234 }
235 var ret []string
236 for _, chaos := range chaosList {
237 if strings.HasPrefix(chaos, toComplete) {
238 ret = append(ret, chaos)
239 }
240 }
241 return ret, cobra.ShellCompDirectiveNoFileComp
242 }
243