...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/cmd/debug.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/cmd

     1  // Copyright 2020 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    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  	// Need to separately support chaos-level completion, so split each chaos apart
    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  // Run debug
   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