github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/support.go (about)

     1  // Copyright (c) 2015-2022 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"fmt"
    22  
    23  	"github.com/fatih/color"
    24  	"github.com/minio/cli"
    25  	json "github.com/minio/colorjson"
    26  	"github.com/minio/madmin-go/v3"
    27  	"github.com/minio/mc/pkg/probe"
    28  	"github.com/minio/minio-go/v7/pkg/set"
    29  	"github.com/minio/pkg/v2/console"
    30  )
    31  
    32  const (
    33  	supportSuccessMsgTag = "SupportSuccessMessage"
    34  	supportErrorMsgTag   = "SupportErrorMessage"
    35  )
    36  
    37  var supportGlobalFlags = append(globalFlags,
    38  	cli.BoolFlag{
    39  		Name:   "dev",
    40  		Usage:  "Development mode",
    41  		Hidden: true,
    42  	},
    43  	cli.BoolFlag{
    44  		Name:  "airgap",
    45  		Usage: "use in environments without network access to SUBNET (e.g. airgapped, firewalled, etc.)",
    46  	},
    47  )
    48  
    49  var supportSubcommands = []cli.Command{
    50  	supportRegisterCmd,
    51  	supportCallhomeCmd,
    52  	supportDiagCmd,
    53  	supportPerfCmd,
    54  	supportInspectCmd,
    55  	supportProfileCmd,
    56  	supportTopCmd,
    57  	supportProxyCmd,
    58  	supportUploadCmd,
    59  }
    60  
    61  var supportCmd = cli.Command{
    62  	Name:            "support",
    63  	Usage:           "support related commands",
    64  	Action:          mainSupport,
    65  	Before:          setGlobalsFromContext,
    66  	Flags:           globalFlags,
    67  	Subcommands:     supportSubcommands,
    68  	HideHelpCommand: true,
    69  }
    70  
    71  func toggleCmdArgs() set.StringSet {
    72  	return set.CreateStringSet("enable", "disable", "status")
    73  }
    74  
    75  func validateToggleCmdArg(arg string) error {
    76  	valid := toggleCmdArgs()
    77  	if !valid.Contains(arg) {
    78  		return fmt.Errorf("Invalid argument '%s'. Must be one of %v", arg, valid)
    79  	}
    80  	return nil
    81  }
    82  
    83  func checkToggleCmdSyntax(ctx *cli.Context) (string, string) {
    84  	if len(ctx.Args()) != 2 {
    85  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
    86  	}
    87  
    88  	arg := ctx.Args().Get(0)
    89  	aliasedURL := ctx.Args().Get(1)
    90  	fatalIf(probe.NewError(validateToggleCmdArg(arg)), "Invalid arguments.")
    91  
    92  	alias, _ := url2Alias(aliasedURL)
    93  
    94  	return alias, arg
    95  }
    96  
    97  func setSuccessMessageColor() {
    98  	console.SetColor(supportSuccessMsgTag, color.New(color.FgGreen, color.Bold))
    99  }
   100  
   101  func setErrorMessageColor() {
   102  	console.SetColor(supportErrorMsgTag, color.New(color.FgYellow, color.Italic))
   103  }
   104  
   105  func featureStatusStr(enabled bool) string {
   106  	if enabled {
   107  		return "enabled"
   108  	}
   109  	return "disabled"
   110  }
   111  
   112  func validateClusterRegistered(alias string, cmdTalksToSubnet bool) string {
   113  	// Non-registered execution allowed only in following scenarios
   114  	// command doesn't talk to subnet: dev mode (`--dev` passed)
   115  	// command talks to subnet: dev+airgapped mode (both `--dev` and `--airgap` passed)
   116  	requireRegistration := !GlobalDevMode
   117  	if cmdTalksToSubnet {
   118  		requireRegistration = !(GlobalDevMode && globalAirgapped)
   119  	}
   120  
   121  	apiKey, e := getSubnetAPIKey(alias)
   122  	if requireRegistration {
   123  		fatalIf(probe.NewError(e), "")
   124  	}
   125  
   126  	return apiKey
   127  }
   128  
   129  // isFeatureEnabled - checks if a feature is enabled in MinIO config
   130  // To be used with configs that can be switched on/off using the `enable` key
   131  // e.g. subSys = logger_webhook, target = logger_webhook:subnet
   132  // Returns true if any of the following is true
   133  // - `enable` is set to `on`
   134  // - `enable` key is not found
   135  // Returns false if any of the following is true
   136  // - given subsystem is not supported by the version of MinIO
   137  // - the given target doesn't exist in the config
   138  // - `enable` is set to `off`
   139  func isFeatureEnabled(alias, subSys, target string) bool {
   140  	client, err := newAdminClient(alias)
   141  	// Create a new MinIO Admin Client
   142  	fatalIf(err, "Unable to initialize admin connection.")
   143  
   144  	if !minioConfigSupportsSubSys(client, subSys) {
   145  		return false
   146  	}
   147  
   148  	scfgs, e := getMinIOSubSysConfig(client, subSys)
   149  	if e != nil {
   150  		// Ignore error if the given target doesn't exist
   151  		// e.g. logger_webhook:subnet doesn't exist when
   152  		// pushing logs to SUBNET has not been enabled
   153  		if e.Error() == fmt.Sprintf("sub-system target '%s' doesn't exist", target) {
   154  			return false
   155  		}
   156  
   157  		fatalIf(probe.NewError(e), fmt.Sprintf("Unable to get server config for '%s'", subSys))
   158  	}
   159  
   160  	if target == madmin.Default {
   161  		target = ""
   162  	}
   163  	for _, scfg := range scfgs {
   164  		if scfg.Target == target {
   165  			enable, found := scfg.Lookup(madmin.EnableKey)
   166  			if !found {
   167  				// if `enable` key is not found, it means that `enable=on`
   168  				return true
   169  			}
   170  			return enable == madmin.EnableOn
   171  		}
   172  	}
   173  	return false
   174  }
   175  
   176  func toJSON(obj interface{}) string {
   177  	jsonBytes, e := json.MarshalIndent(obj, "", " ")
   178  	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
   179  
   180  	return string(jsonBytes)
   181  }
   182  
   183  // mainSupport is the handle for "mc support" command.
   184  func mainSupport(ctx *cli.Context) error {
   185  	commandNotFound(ctx, supportSubcommands)
   186  	return nil
   187  	// Sub-commands like "register", "callhome", "diagnostics" have their own main.
   188  }