cmd/main.go (107 lines of code) (raw):

// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one // or more contributor license agreements. Licensed under the Elastic License 2.0; // you may not use this file except in compliance with the Elastic License 2.0. package main import ( "fmt" "log" "os" "path/filepath" "time" "github.com/elastic/eck-diagnostics/internal" internal_filters "github.com/elastic/eck-diagnostics/internal/filters" "github.com/spf13/cobra" ) const ( operatorNamespaces = "operator-namespaces" resourcesNamespaces = "resources-namespaces" ) var ( filters []string rawLogSelectors []string diagParams = internal.Params{} ) func main() { cmd := &cobra.Command{ Use: "eck-diagnostics", Short: "ECK support diagnostics tool", Long: "Dump ECK and Kubernetes data for support and troubleshooting purposes.", PreRunE: preRunOperations, Version: internal.Version(), RunE: func(_ *cobra.Command, _ []string) error { return internal.Run(diagParams) }, } cmd.Flags().StringVar(&diagParams.DiagnosticImage, "diagnostic-image", internal.DiagnosticImage, "Diagnostic image to be used for stack diagnostics, see run-stack-diagnostics") cmd.Flags().BoolVar(&diagParams.RunStackDiagnostics, "run-stack-diagnostics", true, "Run diagnostics on deployed Elasticsearch clusters and Kibana instances, requires deploying diagnostic Pods into the cluster") cmd.Flags().BoolVar(&diagParams.RunAgentDiagnostics, "run-agent-diagnostics", false, "Run diagnostics on deployed Elastic Agents. Warning: credentials will not be redacted and appear as plain text in the archive") cmd.Flags().StringSliceVarP(&diagParams.OperatorNamespaces, operatorNamespaces, "o", []string{"elastic-system"}, "Comma-separated list of namespace(s) in which operator(s) are running") cmd.Flags().StringSliceVarP(&diagParams.ResourcesNamespaces, resourcesNamespaces, "r", nil, "Comma-separated list of namespace(s) in which resources are managed") cmd.Flags().StringSliceVarP(&filters, "filters", "f", nil, fmt.Sprintf(`Comma-separated list of filters in format "type=name". Example: elasticsearch=my-cluster (Supported types %v)`, internal_filters.ValidTypes)) cmd.Flags().StringArrayVarP(&rawLogSelectors, "log-selectors", "l", nil, "Label selectors to restrict the logs to be collected. Can be specified more than once. Example: -l 'elasticsearch.k8s.elastic.co/node-master=true,elasticsearch.k8s.elastic.co/node-data!=true' -l common.k8s.elastic.co/type=kibana") cmd.Flags().StringVar(&diagParams.ECKVersion, "eck-version", "", "ECK version in use, will try to autodetect if not specified") cmd.Flags().StringVar(&diagParams.OutputDir, "output-directory", "", "Path where to output diagnostic results") cmd.Flags().StringVarP(&diagParams.OutputName, "output-name", "n", fmt.Sprintf("eck-diagnostics-%s.zip", time.Now().Format("2006-01-02T15-04-05")), "Name of the output diagnostics file") cmd.Flags().StringVar(&diagParams.Kubeconfig, "kubeconfig", "", "optional path to kube config, defaults to $HOME/.kube/config") cmd.Flags().BoolVar(&diagParams.Verbose, "verbose", false, "Verbose mode") cmd.Flags().DurationVar(&diagParams.StackDiagnosticsTimeout, "stack-diagnostics-timeout", 5*time.Minute, "Maximum time to wait for Elaticsearch and Kibana diagnostics to complete") if err := cmd.MarkFlagRequired(resourcesNamespaces); err != nil { exitWithError(err) } if err := cmd.Execute(); err != nil { // cobra logs the error already no need to redo that exitWithError(nil) } } func preRunOperations(cmd *cobra.Command, args []string) error { if err := validation(cmd, args); err != nil { return err } return parseFilters(cmd, args) } func validation(_ *cobra.Command, _ []string) error { if diagParams.OutputName == "" { return fmt.Errorf("output-name cannot be empty") } if filepath.Ext(diagParams.OutputName) != ".zip" { return fmt.Errorf("output-name extension must end in '.zip'") } type validations struct { namespaces []string name string } for _, v := range []validations{ { namespaces: diagParams.OperatorNamespaces, name: operatorNamespaces, }, { namespaces: diagParams.ResourcesNamespaces, name: resourcesNamespaces, }, } { if len(v.namespaces) == 0 { return fmt.Errorf("%s is a required parameter", v.name) } for _, ns := range v.namespaces { if ns == "" { return fmt.Errorf("%s cannot be an empty string", v.name) } } } return nil } func parseFilters(_ *cobra.Command, _ []string) error { filters, err := internal_filters.NewTypeFilter(filters) if err != nil { return err } diagParams.Filters = filters logFilters, err := internal_filters.NewLabelFilter(rawLogSelectors) if err != nil { return err } diagParams.LogFilters = logFilters return nil } func exitWithError(err error) { if err != nil { log.Printf("Error: %v", err) } os.Exit(1) }