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