Browse Source

cscli config feature-flags (#2006)

mmetc 2 years ago
parent
commit
e5833699c0
3 changed files with 144 additions and 0 deletions
  1. 1 0
      cmd/crowdsec-cli/config.go
  2. 126 0
      cmd/crowdsec-cli/config_feature_flags.go
  3. 17 0
      pkg/fflag/features.go

+ 1 - 0
cmd/crowdsec-cli/config.go

@@ -16,6 +16,7 @@ func NewConfigCmd() *cobra.Command {
 	cmdConfig.AddCommand(NewConfigShowCmd())
 	cmdConfig.AddCommand(NewConfigBackupCmd())
 	cmdConfig.AddCommand(NewConfigRestoreCmd())
+	cmdConfig.AddCommand(NewConfigFeatureFlagsCmd())
 
 	return cmdConfig
 }

+ 126 - 0
cmd/crowdsec-cli/config_feature_flags.go

@@ -0,0 +1,126 @@
+package main
+
+import (
+	"fmt"
+
+	"github.com/fatih/color"
+	"github.com/spf13/cobra"
+
+	"github.com/crowdsecurity/crowdsec/pkg/fflag"
+)
+
+func runConfigFeatureFlags(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	showRetired, err := flags.GetBool("retired")
+	if err != nil {
+		return err
+	}
+
+	green := color.New(color.FgGreen).SprintFunc()
+	red := color.New(color.FgRed).SprintFunc()
+	yellow := color.New(color.FgYellow).SprintFunc()
+	magenta := color.New(color.FgMagenta).SprintFunc()
+
+	printFeature := func(feat fflag.Feature) {
+		nameDesc := feat.Name
+		if feat.Description != "" {
+			nameDesc += ": " + feat.Description
+		}
+
+		status := red("✗")
+		if feat.IsEnabled() {
+			status = green("✓")
+		}
+
+		fmt.Printf("%s %s", status, nameDesc)
+
+		if feat.State == fflag.DeprecatedState {
+			fmt.Printf("\n  %s %s", yellow("DEPRECATED"), feat.DeprecationMsg)
+		}
+
+		if feat.State == fflag.RetiredState {
+			fmt.Printf("\n  %s %s", magenta("RETIRED"), feat.DeprecationMsg)
+		}
+		fmt.Println()
+	}
+
+	feats := fflag.Crowdsec.GetAllFeatures()
+
+	enabled := []fflag.Feature{}
+	disabled := []fflag.Feature{}
+	retired := []fflag.Feature{}
+
+	for _, feat := range feats {
+		if feat.State == fflag.RetiredState {
+			retired = append(retired, feat)
+			continue
+		}
+		if feat.IsEnabled() {
+			enabled = append(enabled, feat)
+			continue
+		}
+		disabled = append(disabled, feat)
+	}
+
+	if len(enabled) > 0 {
+		fmt.Println(" --- Enabled features ---")
+		fmt.Println()
+
+		for _, feat := range enabled {
+			printFeature(feat)
+		}
+
+		fmt.Println()
+	}
+
+	if len(disabled) > 0 {
+		fmt.Println(" --- Disabled features ---")
+		fmt.Println()
+
+		for _, feat := range disabled {
+			printFeature(feat)
+		}
+
+		fmt.Println()
+	}
+
+	fmt.Println("To enable a feature you can: ")
+	fmt.Println("  - set the environment variable CROWDSEC_FEATURE_<uppercase_feature_name> to true")
+	fmt.Printf("  - add the line '- <feature_name>' to the file %s/feature.yaml\n", csConfig.ConfigPaths.ConfigDir)
+	fmt.Println()
+
+	if len(enabled) == 0 && len(disabled) == 0 {
+		fmt.Println("However, no feature flag is available in this release.")
+		fmt.Println()
+	}
+
+	if showRetired && len(retired) > 0 {
+		fmt.Println(" --- Retired features ---")
+		fmt.Println()
+
+		for _, feat := range retired {
+			printFeature(feat)
+		}
+
+		fmt.Println()
+	}
+
+	return nil
+}
+
+func NewConfigFeatureFlagsCmd() *cobra.Command {
+	cmdConfigFeatureFlags := &cobra.Command{
+		Use:               "feature-flags",
+		Short:             "Displays feature flag status",
+		Long:              `Displays the supported feature flags and their current status.`,
+		Args:              cobra.ExactArgs(0),
+		DisableAutoGenTag: true,
+		RunE:              runConfigFeatureFlags,
+	}
+
+	flags := cmdConfigFeatureFlags.Flags()
+	flags.Bool("retired", false, "Show retired features")
+
+	return cmdConfigFeatureFlags
+}

+ 17 - 0
pkg/fflag/features.go

@@ -262,3 +262,20 @@ func (fr *FeatureRegister) GetEnabledFeatures() []string {
 
 	return ret
 }
+
+// GetAllFeatures returns a slice of all the known features, ordered by name
+func (fr *FeatureRegister) GetAllFeatures() []Feature {
+	ret := make([]Feature, len(fr.features))
+
+	i := 0
+	for _, feat := range fr.features {
+		ret[i] = *feat
+		i++
+	}
+
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].Name < ret[j].Name
+	})
+
+	return ret
+}