Compare commits

..

15 Commits

Author SHA1 Message Date
Alex Jones
391c3fa7a8 Merge pull request #160 from k8sgpt-ai/release-please--branches--main
chore(main): release 0.1.5
2023-03-31 15:08:22 +01:00
github-actions[bot]
8e99076497 chore(main): release 0.1.5 2023-03-31 14:04:36 +00:00
Alex Jones
c2b8732a5c Merge pull request #161 from matthisholleville/feature/add-and-remove-filters
feat: add & remove default filter(s) to analyze.
2023-03-31 15:04:01 +01:00
Matthis Holleville
3ed545f33f feat: rework filters
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-31 15:46:20 +02:00
Matthis Holleville
975813d328 feat: check if filters does not empty on add & remove
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-31 13:57:03 +02:00
Matthis Holleville
9aa0e8960e feat: update filters add & remove to be more consistent
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-31 13:30:59 +02:00
Matthis Holleville
0a124484a2 fix: spelling on dupplicateFilters
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-31 13:02:26 +02:00
Matthis Holleville
30faf84254 feat: remove filter prefix on subcommand
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-31 12:59:19 +02:00
Matthis Holleville
9ebb7de3c0 Merge branch 'main' into feature/add-and-remove-filters 2023-03-31 11:19:40 +02:00
Roberth Strand
9e9cd7083d Merge pull request #166 from matthisholleville/fix/kubecontext-has-no-effect
fix: kubecontext flag has no effect
2023-03-31 11:15:58 +02:00
Matthis Holleville
a8bf45134f fix: kubecontext flag has no effect
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-31 10:41:50 +02:00
Alex Jones
4d5449f97a Merge pull request #165 from k8sgpt-ai/chore/filterlist-file
chore: renamed filter list file
2023-03-31 09:07:39 +01:00
AlexsJones
25f8dc390c chore: renamed filter list file
Signed-off-by: AlexsJones <alexsimonjones@gmail.com>
2023-03-31 09:07:08 +01:00
Matthis Holleville
32ddf6691c feat: add & remove default filter(s) to analyze.
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-30 23:18:43 +02:00
HOLLEVILLE Matthis
6e17c9e285 feat: add filter command add "list" subcommand (#159)
* feat: add filter command add "list" subcommand to display available filters

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* feat: create specific file to filterList

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* feat: rename ListAnalyzers to ListFilters

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

---------

Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-30 20:58:41 +02:00
10 changed files with 331 additions and 13 deletions

View File

@@ -1 +1 @@
{".":"0.1.4"}
{".":"0.1.5"}

View File

@@ -1,5 +1,28 @@
# Changelog
## [0.1.5](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.4...v0.1.5) (2023-03-31)
### Features
* add & remove default filter(s) to analyze. ([32ddf66](https://github.com/k8sgpt-ai/k8sgpt/commit/32ddf6691ce083fd4283a1d5ac4b9f02e90df867))
* add filter command add "list" subcommand ([#159](https://github.com/k8sgpt-ai/k8sgpt/issues/159)) ([6e17c9e](https://github.com/k8sgpt-ai/k8sgpt/commit/6e17c9e285e3871bb8f694b734a8cd6fd02e60f0))
* check if filters does not empty on add & remove ([975813d](https://github.com/k8sgpt-ai/k8sgpt/commit/975813d3284719c877630ad20f90c6fe163283da))
* remove filter prefix on subcommand ([30faf84](https://github.com/k8sgpt-ai/k8sgpt/commit/30faf842541c0be6b6483f71f6cf04d5cafecef5))
* rework filters ([3ed545f](https://github.com/k8sgpt-ai/k8sgpt/commit/3ed545f33fb3ecb3827c03e8c89027c61386c44f))
* update filters add & remove to be more consistent ([9aa0e89](https://github.com/k8sgpt-ai/k8sgpt/commit/9aa0e8960ee340208b4749954c99867842ba58b9))
### Bug Fixes
* kubecontext flag has no effect ([a8bf451](https://github.com/k8sgpt-ai/k8sgpt/commit/a8bf45134ff3a72dc3e531d720f119790faff9d4))
* spelling on dupplicateFilters ([0a12448](https://github.com/k8sgpt-ai/k8sgpt/commit/0a124484a23789376258413e73628c7b1d7abded))
### Other
* renamed filter list file ([25f8dc3](https://github.com/k8sgpt-ai/k8sgpt/commit/25f8dc390cccd66965993f464351e671af11f8ac))
## [0.1.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.3...v0.1.4) (2023-03-30)

View File

@@ -47,6 +47,7 @@ If you install gcc as suggested, the problem will persist. Therefore, you need t
* Currently the default AI provider is OpenAI, you will need to generate an API key from [OpenAI](https://openai.com)
* You can do this by running `k8sgpt generate` to open a browser link to generate it
* Run `k8sgpt auth` to set it in k8sgpt.
* Run `k8sgpt filters` to manage the active filters used by the analyzer. By default, all filters are executed during analysis.
* Run `k8sgpt analyze` to run a scan.
* And use `k8sgpt analyze --explain` to get a more detailed explanation of the issues.
@@ -76,6 +77,7 @@ Available Commands:
analyze This command will find problems within your Kubernetes cluster
auth Authenticate with your chosen backend
completion Generate the autocompletion script for the specified shell
filters Manage filters for analyzing Kubernetes resources
generate Generate Key for your chosen backend (opens browser)
help Help about any command
version Print the version number of k8sgpt
@@ -90,6 +92,36 @@ Flags:
Use "k8sgpt [command] --help" for more information about a command.
```
_Manage filters_
_List filters_
```
k8sgpt filters list
```
_Add default filters_
```
k8sgpt filters add [filter(s)]
```
### Examples :
- Simple filter : `k8sgpt filters add Service`
- Multiple filters : `k8sgpt filters add Ingress,Pod`
_Add default filters_
```
k8sgpt filters remove [filter(s)]
```
### Examples :
- Simple filter : `k8sgpt filters remove Service`
- Multiple filters : `k8sgpt filters remove Ingress,Pod`
_Run a scan with the default analyzers_
```

71
cmd/filters/add.go Normal file
View File

@@ -0,0 +1,71 @@
package filters
import (
"os"
"strings"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var addCmd = &cobra.Command{
Use: "add [filter(s)]",
Short: "Adds one or more new filters.",
Long: `The add command adds one or more new filters to the default set of filters used by the analyze.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
inputFilters := strings.Split(args[0], ",")
availableFilters := analyzer.ListFilters()
// Verify filter exist
invalidFilters := []string{}
for _, f := range inputFilters {
if f == "" {
color.Red("Filter cannot be empty. Please use correct syntax.")
os.Exit(1)
}
foundFilter := false
for _, filter := range availableFilters {
if filter == f {
foundFilter = true
break
}
}
if !foundFilter {
invalidFilters = append(invalidFilters, f)
}
}
if len(invalidFilters) != 0 {
color.Red("Filter %s does not exist. Please use k8sgpt filters list", strings.Join(invalidFilters, ", "))
os.Exit(1)
}
// Get defined active_filters
activeFilters := viper.GetStringSlice("active_filters")
if len(activeFilters) == 0 {
activeFilters = availableFilters
}
mergedFilters := append(activeFilters, inputFilters...)
uniqueFilters, dupplicatedFilters := util.RemoveDuplicates(mergedFilters)
// Verify dupplicate
if len(dupplicatedFilters) != 0 {
color.Red("Duplicate filters found: %s", strings.Join(dupplicatedFilters, ", "))
os.Exit(1)
}
viper.Set("active_filters", uniqueFilters)
if err := viper.WriteConfig(); err != nil {
color.Red("Error writing config file: %s", err.Error())
os.Exit(1)
}
color.Green("Filter %s added", strings.Join(inputFilters, ", "))
},
}

25
cmd/filters/filters.go Normal file
View File

@@ -0,0 +1,25 @@
package filters
import (
"github.com/spf13/cobra"
)
var FiltersCmd = &cobra.Command{
Use: "filters",
Aliases: []string{"filters"},
Short: "Manage filters for analyzing Kubernetes resources",
Long: `The filters command allows you to manage filters that are used to analyze Kubernetes resources.
You can list available filters to analyze resources.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
cmd.Help()
return
}
},
}
func init() {
FiltersCmd.AddCommand(listCmd)
FiltersCmd.AddCommand(addCmd)
FiltersCmd.AddCommand(removeCmd)
}

39
cmd/filters/list.go Normal file
View File

@@ -0,0 +1,39 @@
package filters
import (
"fmt"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var listCmd = &cobra.Command{
Use: "list",
Short: "List available filters",
Long: `The list command displays a list of available filters that can be used to analyze Kubernetes resources.`,
Run: func(cmd *cobra.Command, args []string) {
activeFilters := viper.GetStringSlice("active_filters")
availableFilters := analyzer.ListFilters()
if len(activeFilters) == 0 {
activeFilters = availableFilters
}
inactiveFilters := util.SliceDiff(availableFilters, activeFilters)
fmt.Printf(color.YellowString("Active: \n"))
for _, filter := range activeFilters {
fmt.Printf("> %s\n", color.GreenString(filter))
}
// display inactive filters
if len(inactiveFilters) != 0 {
fmt.Printf(color.YellowString("Unused: \n"))
for _, filter := range inactiveFilters {
fmt.Printf("> %s\n", color.RedString(filter))
}
}
},
}

72
cmd/filters/remove.go Normal file
View File

@@ -0,0 +1,72 @@
package filters
import (
"os"
"strings"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var removeCmd = &cobra.Command{
Use: "remove [filter(s)]",
Short: "Remove one or more filters.",
Long: `The add command remove one or more filters to the default set of filters used by the analyze.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
inputFilters := strings.Split(args[0], ",")
// Get defined active_filters
activeFilters := viper.GetStringSlice("active_filters")
if len(activeFilters) == 0 {
activeFilters = analyzer.ListFilters()
}
// Check if input input filters is not empty
for _, f := range inputFilters {
if f == "" {
color.Red("Filter cannot be empty. Please use correct syntax.")
os.Exit(1)
}
}
// verify dupplicate filters example: k8sgpt filters remove Pod Pod
uniqueFilters, dupplicatedFilters := util.RemoveDuplicates(inputFilters)
if len(dupplicatedFilters) != 0 {
color.Red("Duplicate filters found: %s", strings.Join(dupplicatedFilters, ", "))
os.Exit(1)
}
// Verify if filter exist in config file and update default_filter
filterNotFound := []string{}
for _, filter := range uniqueFilters {
foundFilter := false
for i, f := range activeFilters {
if f == filter {
foundFilter = true
activeFilters = append(activeFilters[:i], activeFilters[i+1:]...)
break
}
}
if !foundFilter {
filterNotFound = append(filterNotFound, filter)
}
}
if len(filterNotFound) != 0 {
color.Red("Filter(s) %s does not exist in configuration file. Please use k8sgpt filters add.", strings.Join(filterNotFound, ", "))
os.Exit(1)
}
viper.Set("active_filters", activeFilters)
if err := viper.WriteConfig(); err != nil {
color.Red("Error writing config file: %s", err.Error())
os.Exit(1)
}
color.Green("Filter(s) %s removed", strings.Join(inputFilters, ", "))
},
}

View File

@@ -4,6 +4,7 @@ import (
"os"
"path/filepath"
"github.com/k8sgpt-ai/k8sgpt/cmd/filters"
"github.com/k8sgpt-ai/k8sgpt/cmd/generate"
"k8s.io/client-go/util/homedir"
@@ -51,6 +52,7 @@ func init() {
}
rootCmd.AddCommand(auth.AuthCmd)
rootCmd.AddCommand(analyze.AnalyzeCmd)
rootCmd.AddCommand(filters.FiltersCmd)
rootCmd.AddCommand(generate.GenerateCmd)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.yaml)")
rootCmd.PersistentFlags().StringVar(&kubecontext, "kubecontext", "", "Kubernetes context to use. Only required if out-of-cluster.")
@@ -59,15 +61,6 @@ func init() {
// when this action is called directly.
// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
//Initialise the kubeconfig
kubernetesClient, err := kubernetes.NewClient(kubecontext, kubeconfig)
if err != nil {
color.Red("Error initialising kubernetes client: %v", err)
os.Exit(1)
}
viper.Set("kubernetesClient", kubernetesClient)
}
// initConfig reads in config file and ENV variables if set.
@@ -88,6 +81,15 @@ func initConfig() {
viper.SafeWriteConfig()
}
//Initialise the kubeconfig
kubernetesClient, err := kubernetes.NewClient(kubecontext, kubeconfig)
if err != nil {
color.Red("Error initialising kubernetes client: %v", err)
os.Exit(1)
}
viper.Set("kubernetesClient", kubernetesClient)
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.

View File

@@ -24,8 +24,10 @@ func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfigur
client *kubernetes.Client,
aiClient ai.IAI, analysisResults *[]Analysis) error {
// if there are no filters selected then run all of them
if len(filters) == 0 {
activeFilters := viper.GetStringSlice("active_filters")
// if there are no filters selected and no active_filters then run all of them
if len(filters) == 0 && len(activeFilters) == 0 {
for _, analyzer := range analyzerMap {
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
return err
@@ -34,7 +36,20 @@ func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfigur
return nil
}
for _, filter := range filters {
// if the filters flag is specified
if len(filters) != 0 {
for _, filter := range filters {
if analyzer, ok := analyzerMap[filter]; ok {
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
return err
}
}
}
return nil
}
// use active_filters
for _, filter := range activeFilters {
if analyzer, ok := analyzerMap[filter]; ok {
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
return err
@@ -81,3 +96,11 @@ func ParseViaAI(ctx context.Context, config *AnalysisConfiguration,
}
return response, nil
}
func ListFilters() []string {
keys := make([]string, 0, len(analyzerMap))
for k := range analyzerMap {
keys = append(keys, k)
}
return keys
}

View File

@@ -65,3 +65,34 @@ func GetParent(client *kubernetes.Client, meta metav1.ObjectMeta) (string, bool)
}
return meta.Name, false
}
func RemoveDuplicates(slice []string) ([]string, []string) {
set := make(map[string]bool)
duplicates := []string{}
for _, val := range slice {
if _, ok := set[val]; !ok {
set[val] = true
} else {
duplicates = append(duplicates, val)
}
}
uniqueSlice := make([]string, 0, len(set))
for val := range set {
uniqueSlice = append(uniqueSlice, val)
}
return uniqueSlice, duplicates
}
func SliceDiff(source, dest []string) []string {
mb := make(map[string]struct{}, len(dest))
for _, x := range dest {
mb[x] = struct{}{}
}
var diff []string
for _, x := range source {
if _, found := mb[x]; !found {
diff = append(diff, x)
}
}
return diff
}