mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2025-09-10 19:49:18 +00:00
feat: add & remove default filter(s) to analyze.
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
This commit is contained in:
38
README.md
38
README.md
@@ -47,7 +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)
|
* 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
|
* 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 auth` to set it in k8sgpt.
|
||||||
* Run `k8sgpt filters` to manage filters.
|
* Run `k8sgpt filters` to manage the default filters used by the analyzer. By default, all filters are executed during analysis.
|
||||||
* Run `k8sgpt analyze` to run a scan.
|
* Run `k8sgpt analyze` to run a scan.
|
||||||
* And use `k8sgpt analyze --explain` to get a more detailed explanation of the issues.
|
* And use `k8sgpt analyze --explain` to get a more detailed explanation of the issues.
|
||||||
|
|
||||||
@@ -92,6 +92,36 @@ Flags:
|
|||||||
Use "k8sgpt [command] --help" for more information about a command.
|
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_
|
_Run a scan with the default analyzers_
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -100,12 +130,6 @@ k8sgpt auth
|
|||||||
k8sgpt analyze --explain
|
k8sgpt analyze --explain
|
||||||
```
|
```
|
||||||
|
|
||||||
_List filters_
|
|
||||||
|
|
||||||
```
|
|
||||||
k8sgpt filters list
|
|
||||||
```
|
|
||||||
|
|
||||||
_Filter on resource_
|
_Filter on resource_
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@@ -20,4 +20,6 @@ var FiltersCmd = &cobra.Command{
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
FiltersCmd.AddCommand(filterListCmd)
|
FiltersCmd.AddCommand(filterListCmd)
|
||||||
|
FiltersCmd.AddCommand(filtersAddCmd)
|
||||||
|
FiltersCmd.AddCommand(filtersRemoveCmd)
|
||||||
}
|
}
|
||||||
|
65
cmd/filters/filtersAdd.go
Normal file
65
cmd/filters/filtersAdd.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
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 filtersAddCmd = &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.MinimumNArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
// Verify filter exist
|
||||||
|
invalidFilters := []string{}
|
||||||
|
for _, f := range args {
|
||||||
|
foundFilter := false
|
||||||
|
for _, filter := range analyzer.ListFilters() {
|
||||||
|
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 default_filters
|
||||||
|
defaultFilters := viper.GetStringSlice("default_filters")
|
||||||
|
if len(defaultFilters) == 0 {
|
||||||
|
defaultFilters = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedFilters := append(defaultFilters, args...)
|
||||||
|
|
||||||
|
uniqueFilters, dupplicateFilters := util.RemoveDuplicates(mergedFilters)
|
||||||
|
|
||||||
|
// Verify dupplicate
|
||||||
|
if len(dupplicateFilters) != 0 {
|
||||||
|
color.Red("Duplicate filters found: %s", strings.Join(dupplicateFilters, ", "))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.Set("default_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(args, ", "))
|
||||||
|
},
|
||||||
|
}
|
62
cmd/filters/filtersRemove.go
Normal file
62
cmd/filters/filtersRemove.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package filters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var filtersRemoveCmd = &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.MinimumNArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
// Get defined default_filters
|
||||||
|
defaultFilters := viper.GetStringSlice("default_filters")
|
||||||
|
if len(defaultFilters) == 0 {
|
||||||
|
defaultFilters = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify dupplicate filters example: k8sgpt filters remove Pod Pod
|
||||||
|
uniqueFilters, dupplicateFilters := util.RemoveDuplicates(args)
|
||||||
|
if len(dupplicateFilters) != 0 {
|
||||||
|
color.Red("Duplicate filters found: %s", strings.Join(dupplicateFilters, ", "))
|
||||||
|
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 defaultFilters {
|
||||||
|
if f == filter {
|
||||||
|
foundFilter = true
|
||||||
|
defaultFilters = append(defaultFilters[:i], defaultFilters[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("default_filters", defaultFilters)
|
||||||
|
|
||||||
|
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(args, ", "))
|
||||||
|
},
|
||||||
|
}
|
@@ -24,8 +24,10 @@ func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfigur
|
|||||||
client *kubernetes.Client,
|
client *kubernetes.Client,
|
||||||
aiClient ai.IAI, analysisResults *[]Analysis) error {
|
aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||||
|
|
||||||
// if there are no filters selected then run all of them
|
defaultFilters := viper.GetStringSlice("default_filters")
|
||||||
if len(filters) == 0 {
|
|
||||||
|
// if there are no filters selected and no default_filters then run all of them
|
||||||
|
if len(filters) == 0 && len(defaultFilters) == 0 {
|
||||||
for _, analyzer := range analyzerMap {
|
for _, analyzer := range analyzerMap {
|
||||||
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -34,6 +36,8 @@ func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfigur
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the filters flag is specified
|
||||||
|
if len(filters) != 0 {
|
||||||
for _, filter := range filters {
|
for _, filter := range filters {
|
||||||
if analyzer, ok := analyzerMap[filter]; ok {
|
if analyzer, ok := analyzerMap[filter]; ok {
|
||||||
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
||||||
@@ -44,6 +48,17 @@ func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfigur
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use default_filters
|
||||||
|
for _, filter := range defaultFilters {
|
||||||
|
if analyzer, ok := analyzerMap[filter]; ok {
|
||||||
|
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func ParseViaAI(ctx context.Context, config *AnalysisConfiguration,
|
func ParseViaAI(ctx context.Context, config *AnalysisConfiguration,
|
||||||
aiClient ai.IAI, prompt []string) (string, error) {
|
aiClient ai.IAI, prompt []string) (string, error) {
|
||||||
// parse the text with the AI backend
|
// parse the text with the AI backend
|
||||||
|
@@ -65,3 +65,20 @@ func GetParent(client *kubernetes.Client, meta metav1.ObjectMeta) (string, bool)
|
|||||||
}
|
}
|
||||||
return meta.Name, false
|
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
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user