...

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 2021 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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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  	// Need to separately support chaos-level completion, so split each chaos apart
    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  // Run debug
   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  	// FIXME: get context from parameter
   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