mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2025-09-29 00:36:50 +00:00
refactor: first try with more interfaces
Signed-off-by: Thomas Schuetz <thomas.schuetz@t-sc.eu>
This commit is contained in:
@@ -2,18 +2,14 @@ package analyze
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||||
"github.com/schollz/progressbar/v3"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -69,75 +65,26 @@ var AnalyzeCmd = &cobra.Command{
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
// Get kubernetes client from viper
|
// Get kubernetes client from viper
|
||||||
client := viper.Get("kubernetesClient").(*kubernetes.Client)
|
client := viper.Get("kubernetesClient").(*kubernetes.Client)
|
||||||
// Analysis configuration
|
// AnalysisResult configuration
|
||||||
config := &analyzer.AnalysisConfiguration{
|
|
||||||
|
analysis := &analysis.Analysis{
|
||||||
|
Context: ctx,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
NoCache: nocache,
|
NoCache: nocache,
|
||||||
Explain: explain,
|
Explain: explain,
|
||||||
|
AIClient: aiClient,
|
||||||
|
Filters: filters,
|
||||||
|
Client: client,
|
||||||
}
|
}
|
||||||
|
|
||||||
var analysisResults *[]analyzer.Analysis = &[]analyzer.Analysis{}
|
// Run analysis
|
||||||
if err := analyzer.RunAnalysis(ctx, filters, config, client,
|
_ = analysis.RunAnalysis()
|
||||||
aiClient, analysisResults); err != nil {
|
|
||||||
color.Red("Error: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(*analysisResults) == 0 {
|
analysis.PrintAnalysisResult()
|
||||||
color.Green("{ \"status\": \"OK\" }")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
var bar = progressbar.Default(int64(len(*analysisResults)))
|
|
||||||
if !explain {
|
|
||||||
bar.Clear()
|
|
||||||
}
|
|
||||||
var printOutput []analyzer.Analysis
|
|
||||||
|
|
||||||
for _, analysis := range *analysisResults {
|
|
||||||
|
|
||||||
if explain {
|
|
||||||
parsedText, err := analyzer.ParseViaAI(ctx, config, aiClient, analysis.Error)
|
|
||||||
if err != nil {
|
|
||||||
// Check for exhaustion
|
|
||||||
if strings.Contains(err.Error(), "status code: 429") {
|
|
||||||
color.Red("Exhausted API quota. Please try again later")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
color.Red("Error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
analysis.Details = parsedText
|
|
||||||
bar.Add(1)
|
|
||||||
}
|
|
||||||
printOutput = append(printOutput, analysis)
|
|
||||||
}
|
|
||||||
|
|
||||||
// print results
|
|
||||||
for n, analysis := range printOutput {
|
|
||||||
|
|
||||||
switch output {
|
|
||||||
case "json":
|
|
||||||
analysis.Error = analysis.Error[0:]
|
|
||||||
j, err := json.Marshal(analysis)
|
|
||||||
if err != nil {
|
|
||||||
color.Red("Error: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
fmt.Println(string(j))
|
|
||||||
default:
|
|
||||||
fmt.Printf("%s %s(%s)\n", color.CyanString("%d", n),
|
|
||||||
color.YellowString(analysis.Name), color.CyanString(analysis.ParentObject))
|
|
||||||
for _, err := range analysis.Error {
|
|
||||||
fmt.Printf("- %s %s\n", color.RedString("Error:"), color.RedString(err))
|
|
||||||
}
|
|
||||||
fmt.Println(color.GreenString(analysis.Details + "\n"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
// namespace flag
|
// namespace flag
|
||||||
AnalyzeCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace to analyze")
|
AnalyzeCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace to analyze")
|
||||||
// no cache flag
|
// no cache flag
|
||||||
|
4
go.mod
4
go.mod
@@ -5,7 +5,6 @@ go 1.20
|
|||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.15.0
|
github.com/fatih/color v1.15.0
|
||||||
github.com/sashabaranov/go-openai v1.5.7
|
github.com/sashabaranov/go-openai v1.5.7
|
||||||
github.com/schollz/progressbar/v3 v3.13.1
|
|
||||||
github.com/spf13/cobra v1.6.1
|
github.com/spf13/cobra v1.6.1
|
||||||
github.com/spf13/viper v1.15.0
|
github.com/spf13/viper v1.15.0
|
||||||
golang.org/x/term v0.6.0
|
golang.org/x/term v0.6.0
|
||||||
@@ -37,14 +36,11 @@ require (
|
|||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
|
||||||
github.com/spf13/afero v1.9.5 // indirect
|
github.com/spf13/afero v1.9.5 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
11
go.sum
11
go.sum
@@ -173,7 +173,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
|||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
@@ -192,13 +191,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
|
||||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
|
||||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -217,17 +211,12 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
|
|||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sashabaranov/go-openai v1.5.7 h1:8DGgRG+P7yWixte5j720y6yiXgY3Hlgcd0gcpHdltfo=
|
github.com/sashabaranov/go-openai v1.5.7 h1:8DGgRG+P7yWixte5j720y6yiXgY3Hlgcd0gcpHdltfo=
|
||||||
github.com/sashabaranov/go-openai v1.5.7/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
github.com/sashabaranov/go-openai v1.5.7/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||||
github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
|
|
||||||
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||||
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||||
|
65
pkg/analysis/analysis.go
Normal file
65
pkg/analysis/analysis.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package analysis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Analysis struct {
|
||||||
|
Context context.Context
|
||||||
|
Namespace string
|
||||||
|
NoCache bool
|
||||||
|
Explain bool
|
||||||
|
AIClient ai.IAI
|
||||||
|
Filters []string
|
||||||
|
Client *kubernetes.Client
|
||||||
|
analysisResults []common.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analysis) RunAnalysis() error {
|
||||||
|
|
||||||
|
activeFilters := viper.GetStringSlice("active_filters")
|
||||||
|
analyzerList := analyzer.GetAnalyzerList()
|
||||||
|
|
||||||
|
// if there are no filters selected and no active_filters then run all of them
|
||||||
|
if len(a.Filters) == 0 && len(activeFilters) == 0 {
|
||||||
|
for _, al := range analyzerList {
|
||||||
|
thisanalysis, _ := analyzer.NewAnalyzer(al, a.Client, a.Context, a.Namespace)
|
||||||
|
err := thisanalysis.Analyze()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error running analysis: ", err)
|
||||||
|
}
|
||||||
|
a.analysisResults = append(a.analysisResults, thisanalysis.GetResult()...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the filters flag is specified
|
||||||
|
if len(a.Filters) != 0 {
|
||||||
|
for _, filter := range a.Filters {
|
||||||
|
for _, ali := range analyzerList {
|
||||||
|
if filter == ali {
|
||||||
|
thisanalysis, _ := analyzer.NewAnalyzer(ali, a.Client, a.Context, a.Namespace)
|
||||||
|
err := thisanalysis.Analyze()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error running analysis: ", err)
|
||||||
|
}
|
||||||
|
a.analysisResults = append(a.analysisResults, thisanalysis.GetResult()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analysis) PrintAnalysisResult() {
|
||||||
|
for _, result := range a.analysisResults {
|
||||||
|
fmt.Println(result)
|
||||||
|
}
|
||||||
|
}
|
@@ -2,71 +2,88 @@ package analyzer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"fmt"
|
||||||
"strings"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/hpa"
|
||||||
"github.com/fatih/color"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/ingress"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/pod"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/pvc"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/rs"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/service"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var coreAnalyzerMap = map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
type IAnalyzer interface {
|
||||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error{
|
Analyze() error
|
||||||
"Pod": AnalyzePod,
|
GetResult() []common.Result
|
||||||
"ReplicaSet": AnalyzeReplicaSet,
|
|
||||||
"PersistentVolumeClaim": AnalyzePersistentVolumeClaim,
|
|
||||||
"Service": AnalyzeEndpoints,
|
|
||||||
"Ingress": AnalyzeIngress,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var additionalAnalyzerMap = map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
const (
|
||||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error{
|
PodAnalyzerName = "Pod"
|
||||||
"HorizontalPodAutoScaler": AnalyzeHpa,
|
ReplicaSetAnalyzerName = "ReplicaSet"
|
||||||
|
PersistentVolumeClaimAnalyzerName = "PersistentVolumeClaim"
|
||||||
|
ServiceAnalyzerName = "Service"
|
||||||
|
IngressAnalyzerName = "Ingress"
|
||||||
|
HPAAnalyzerName = "HorizontalPodAutoScaler"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
coreAnalyzerList = []string{
|
||||||
|
PodAnalyzerName,
|
||||||
|
ReplicaSetAnalyzerName,
|
||||||
|
PersistentVolumeClaimAnalyzerName,
|
||||||
|
ServiceAnalyzerName,
|
||||||
|
IngressAnalyzerName,
|
||||||
|
HPAAnalyzerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfiguration,
|
additionalAnalyzers = []string{
|
||||||
client *kubernetes.Client,
|
HPAAnalyzerName,
|
||||||
aiClient ai.IAI, analysisResults *[]Analysis) error {
|
|
||||||
|
|
||||||
activeFilters := viper.GetStringSlice("active_filters")
|
|
||||||
|
|
||||||
analyzerMap := getAnalyzerMap()
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
return nil
|
|
||||||
|
func NewAnalyzer(analyzer string, client *kubernetes.Client, context context.Context, namespace string) (IAnalyzer, error) {
|
||||||
|
analyzerConfig := common.Analyzer{
|
||||||
|
Namespace: namespace,
|
||||||
|
Context: context,
|
||||||
|
Client: client,
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the filters flag is specified
|
analyzerConfig.PreAnalysis = make(map[string]common.PreAnalysis)
|
||||||
if len(filters) != 0 {
|
|
||||||
for _, filter := range filters {
|
switch analyzer {
|
||||||
if analyzer, ok := analyzerMap[filter]; ok {
|
case PodAnalyzerName:
|
||||||
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
return &pod.PodAnalyzer{
|
||||||
return err
|
Analyzer: analyzerConfig,
|
||||||
|
}, nil
|
||||||
|
case ReplicaSetAnalyzerName:
|
||||||
|
return &rs.ReplicaSetAnalyzer{
|
||||||
|
Analyzer: analyzerConfig,
|
||||||
|
}, nil
|
||||||
|
case IngressAnalyzerName:
|
||||||
|
return &ingress.IngressAnalyzer{
|
||||||
|
Analyzer: analyzerConfig,
|
||||||
|
}, nil
|
||||||
|
case HPAAnalyzerName:
|
||||||
|
return &hpa.HPAAnalyzer{
|
||||||
|
Analyzer: analyzerConfig,
|
||||||
|
}, nil
|
||||||
|
case PersistentVolumeClaimAnalyzerName:
|
||||||
|
return &pvc.PvcAnalyzer{
|
||||||
|
Analyzer: analyzerConfig,
|
||||||
|
}, nil
|
||||||
|
case ServiceAnalyzerName:
|
||||||
|
return &service.ServiceAnalyzer{
|
||||||
|
Analyzer: analyzerConfig,
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Analyzer %s not supported", analyzer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// use active_filters
|
/*
|
||||||
for _, filter := range activeFilters {
|
func ParseViaAI(ctx context.Context, config *analysis.Analysis,
|
||||||
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,
|
|
||||||
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
|
||||||
inputKey := strings.Join(prompt, " ")
|
inputKey := strings.Join(prompt, " ")
|
||||||
@@ -103,35 +120,39 @@ func ParseViaAI(ctx context.Context, config *AnalysisConfiguration,
|
|||||||
}
|
}
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
func ListFilters() ([]string, []string) {
|
func ListFilters() ([]string, []string) {
|
||||||
coreKeys := make([]string, 0, len(coreAnalyzerMap))
|
coreKeys := []string{}
|
||||||
for k := range coreAnalyzerMap {
|
for _, filter := range coreAnalyzerList {
|
||||||
coreKeys = append(coreKeys, k)
|
coreKeys = append(coreKeys, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
additionalKeys := make([]string, 0, len(additionalAnalyzerMap))
|
additionalKeys := []string{}
|
||||||
for k := range additionalAnalyzerMap {
|
for _, filter := range additionalAnalyzers {
|
||||||
additionalKeys = append(additionalKeys, k)
|
coreKeys = append(additionalKeys, filter)
|
||||||
}
|
}
|
||||||
return coreKeys, additionalKeys
|
return coreKeys, additionalKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAnalyzerMap() map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
func GetAnalyzerList() []string {
|
||||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
list := []string{}
|
||||||
|
|
||||||
mergedMap := make(map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
list = append(list, coreAnalyzerList...)
|
||||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error)
|
list = append(list, additionalAnalyzers...)
|
||||||
|
|
||||||
// add core analyzer
|
list = removeDuplicateStr(list)
|
||||||
for key, value := range coreAnalyzerMap {
|
|
||||||
mergedMap[key] = value
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
// add additional analyzer
|
func removeDuplicateStr(strSlice []string) []string {
|
||||||
for key, value := range additionalAnalyzerMap {
|
allKeys := make(map[string]bool)
|
||||||
mergedMap[key] = value
|
list := []string{}
|
||||||
|
for _, item := range strSlice {
|
||||||
|
if _, value := allKeys[item]; !value {
|
||||||
|
allKeys[item] = true
|
||||||
|
list = append(list, item)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return mergedMap
|
return list
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package analyzer
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
@@ -1,16 +1,28 @@
|
|||||||
package analyzer
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
autov1 "k8s.io/api/autoscaling/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkv1 "k8s.io/api/networking/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AnalysisConfiguration struct {
|
type Analyzer struct {
|
||||||
|
Client *kubernetes.Client
|
||||||
|
Context context.Context
|
||||||
Namespace string
|
Namespace string
|
||||||
NoCache bool
|
PreAnalysis map[string]PreAnalysis
|
||||||
Explain bool
|
Result []Result
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Error []string `json:"error"`
|
||||||
|
Details string `json:"details"`
|
||||||
|
ParentObject string `json:"parentObject"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PreAnalysis struct {
|
type PreAnalysis struct {
|
||||||
@@ -19,14 +31,6 @@ type PreAnalysis struct {
|
|||||||
ReplicaSet appsv1.ReplicaSet
|
ReplicaSet appsv1.ReplicaSet
|
||||||
PersistentVolumeClaim v1.PersistentVolumeClaim
|
PersistentVolumeClaim v1.PersistentVolumeClaim
|
||||||
Endpoint v1.Endpoints
|
Endpoint v1.Endpoints
|
||||||
Ingress networkingv1.Ingress
|
Ingress networkv1.Ingress
|
||||||
HorizontalPodAutoscalers autoscalingv1.HorizontalPodAutoscaler
|
HorizontalPodAutoscalers autov1.HorizontalPodAutoscaler
|
||||||
}
|
|
||||||
|
|
||||||
type Analysis struct {
|
|
||||||
Kind string `json:"kind"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Error []string `json:"error"`
|
|
||||||
Details string `json:"details"`
|
|
||||||
ParentObject string `json:"parentObject"`
|
|
||||||
}
|
}
|
@@ -1,25 +1,22 @@
|
|||||||
package analyzer
|
package hpa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
type HPAAnalyzer struct {
|
||||||
analysisResults *[]Analysis) error {
|
common.Analyzer
|
||||||
|
}
|
||||||
|
|
||||||
list, err := client.GetClient().AutoscalingV1().HorizontalPodAutoscalers(config.Namespace).List(ctx, metav1.ListOptions{})
|
func (a *HPAAnalyzer) Analyze() error {
|
||||||
|
list, err := a.Client.GetClient().AutoscalingV1().HorizontalPodAutoscalers(a.Namespace).List(a.Context, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var preAnalysis = map[string]PreAnalysis{}
|
|
||||||
|
|
||||||
for _, hpa := range list.Items {
|
for _, hpa := range list.Items {
|
||||||
var failures []string
|
var failures []string
|
||||||
|
|
||||||
@@ -29,22 +26,22 @@ func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kube
|
|||||||
|
|
||||||
switch scaleTargetRef.Kind {
|
switch scaleTargetRef.Kind {
|
||||||
case "Deployment":
|
case "Deployment":
|
||||||
_, err := client.GetClient().AppsV1().Deployments(config.Namespace).Get(ctx, scaleTargetRef.Name, metav1.GetOptions{})
|
_, err := a.Client.GetClient().AppsV1().Deployments(a.Namespace).Get(a.Context, scaleTargetRef.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scaleTargetRefNotFound = true
|
scaleTargetRefNotFound = true
|
||||||
}
|
}
|
||||||
case "ReplicationController":
|
case "ReplicationController":
|
||||||
_, err := client.GetClient().CoreV1().ReplicationControllers(config.Namespace).Get(ctx, scaleTargetRef.Name, metav1.GetOptions{})
|
_, err := a.Client.GetClient().CoreV1().ReplicationControllers(a.Namespace).Get(a.Context, scaleTargetRef.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scaleTargetRefNotFound = true
|
scaleTargetRefNotFound = true
|
||||||
}
|
}
|
||||||
case "ReplicaSet":
|
case "ReplicaSet":
|
||||||
_, err := client.GetClient().AppsV1().ReplicaSets(config.Namespace).Get(ctx, scaleTargetRef.Name, metav1.GetOptions{})
|
_, err := a.Client.GetClient().AppsV1().ReplicaSets(a.Namespace).Get(a.Context, scaleTargetRef.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scaleTargetRefNotFound = true
|
scaleTargetRefNotFound = true
|
||||||
}
|
}
|
||||||
case "StatefulSet":
|
case "StatefulSet":
|
||||||
_, err := client.GetClient().AppsV1().StatefulSets(config.Namespace).Get(ctx, scaleTargetRef.Name, metav1.GetOptions{})
|
_, err := a.Client.GetClient().AppsV1().StatefulSets(a.Namespace).Get(a.Context, scaleTargetRef.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scaleTargetRefNotFound = true
|
scaleTargetRefNotFound = true
|
||||||
}
|
}
|
||||||
@@ -57,7 +54,7 @@ func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kube
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
preAnalysis[fmt.Sprintf("%s/%s", hpa.Namespace, hpa.Name)] = PreAnalysis{
|
a.PreAnalysis[fmt.Sprintf("%s/%s", hpa.Namespace, hpa.Name)] = common.PreAnalysis{
|
||||||
HorizontalPodAutoscalers: hpa,
|
HorizontalPodAutoscalers: hpa,
|
||||||
FailureDetails: failures,
|
FailureDetails: failures,
|
||||||
}
|
}
|
||||||
@@ -65,17 +62,20 @@ func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kube
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range preAnalysis {
|
for key, value := range a.PreAnalysis {
|
||||||
var currentAnalysis = Analysis{
|
var currentAnalysis = common.Result{
|
||||||
Kind: "HorizontalPodAutoscaler",
|
Kind: "HorizontalPodAutoscaler",
|
||||||
Name: key,
|
Name: key,
|
||||||
Error: value.FailureDetails,
|
Error: value.FailureDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, _ := util.GetParent(client, value.Ingress.ObjectMeta)
|
parent, _ := util.GetParent(a.Client, value.Ingress.ObjectMeta)
|
||||||
currentAnalysis.ParentObject = parent
|
currentAnalysis.ParentObject = parent
|
||||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
a.Result = append(a.Result, currentAnalysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *HPAAnalyzer) GetResult() []common.Result {
|
||||||
|
return a.Result
|
||||||
|
}
|
@@ -1,25 +1,23 @@
|
|||||||
package analyzer
|
package ingress
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
type IngressAnalyzer struct {
|
||||||
analysisResults *[]Analysis) error {
|
common.Analyzer
|
||||||
|
}
|
||||||
|
|
||||||
list, err := client.GetClient().NetworkingV1().Ingresses(config.Namespace).List(ctx, metav1.ListOptions{})
|
func (a *IngressAnalyzer) Analyze() error {
|
||||||
|
list, err := a.Client.GetClient().NetworkingV1().Ingresses(a.Namespace).List(a.Context, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var preAnalysis = map[string]PreAnalysis{}
|
|
||||||
|
|
||||||
for _, ing := range list.Items {
|
for _, ing := range list.Items {
|
||||||
var failures []string
|
var failures []string
|
||||||
|
|
||||||
@@ -36,7 +34,7 @@ func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *
|
|||||||
|
|
||||||
// check if ingressclass exist
|
// check if ingressclass exist
|
||||||
if ingressClassName != nil {
|
if ingressClassName != nil {
|
||||||
_, err := client.GetClient().NetworkingV1().IngressClasses().Get(ctx, *ingressClassName, metav1.GetOptions{})
|
_, err := a.Client.GetClient().NetworkingV1().IngressClasses().Get(a.Context, *ingressClassName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failures = append(failures, fmt.Sprintf("Ingress uses the ingress class %s which does not exist.", *ingressClassName))
|
failures = append(failures, fmt.Sprintf("Ingress uses the ingress class %s which does not exist.", *ingressClassName))
|
||||||
}
|
}
|
||||||
@@ -46,7 +44,7 @@ func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *
|
|||||||
for _, rule := range ing.Spec.Rules {
|
for _, rule := range ing.Spec.Rules {
|
||||||
// loop over paths
|
// loop over paths
|
||||||
for _, path := range rule.HTTP.Paths {
|
for _, path := range rule.HTTP.Paths {
|
||||||
_, err := client.GetClient().CoreV1().Services(ing.Namespace).Get(ctx, path.Backend.Service.Name, metav1.GetOptions{})
|
_, err := a.Client.GetClient().CoreV1().Services(ing.Namespace).Get(a.Context, path.Backend.Service.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failures = append(failures, fmt.Sprintf("Ingress uses the service %s/%s which does not exist.", ing.Namespace, path.Backend.Service.Name))
|
failures = append(failures, fmt.Sprintf("Ingress uses the service %s/%s which does not exist.", ing.Namespace, path.Backend.Service.Name))
|
||||||
}
|
}
|
||||||
@@ -54,13 +52,13 @@ func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tls := range ing.Spec.TLS {
|
for _, tls := range ing.Spec.TLS {
|
||||||
_, err := client.GetClient().CoreV1().Secrets(ing.Namespace).Get(ctx, tls.SecretName, metav1.GetOptions{})
|
_, err := a.Client.GetClient().CoreV1().Secrets(ing.Namespace).Get(a.Context, tls.SecretName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failures = append(failures, fmt.Sprintf("Ingress uses the secret %s/%s as a TLS certificate which does not exist.", ing.Namespace, tls.SecretName))
|
failures = append(failures, fmt.Sprintf("Ingress uses the secret %s/%s as a TLS certificate which does not exist.", ing.Namespace, tls.SecretName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
preAnalysis[fmt.Sprintf("%s/%s", ing.Namespace, ing.Name)] = PreAnalysis{
|
a.PreAnalysis[fmt.Sprintf("%s/%s", ing.Namespace, ing.Name)] = common.PreAnalysis{
|
||||||
Ingress: ing,
|
Ingress: ing,
|
||||||
FailureDetails: failures,
|
FailureDetails: failures,
|
||||||
}
|
}
|
||||||
@@ -68,17 +66,20 @@ func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range preAnalysis {
|
for key, value := range a.PreAnalysis {
|
||||||
var currentAnalysis = Analysis{
|
var currentAnalysis = common.Result{
|
||||||
Kind: "Ingress",
|
Kind: "Ingress",
|
||||||
Name: key,
|
Name: key,
|
||||||
Error: value.FailureDetails,
|
Error: value.FailureDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, _ := util.GetParent(client, value.Ingress.ObjectMeta)
|
parent, _ := util.GetParent(a.Client, value.Ingress.ObjectMeta)
|
||||||
currentAnalysis.ParentObject = parent
|
currentAnalysis.ParentObject = parent
|
||||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
a.Result = append(a.Result, currentAnalysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *IngressAnalyzer) GetResult() []common.Result {
|
||||||
|
return a.Result
|
||||||
|
}
|
@@ -1,25 +1,22 @@
|
|||||||
package analyzer
|
package pod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AnalyzePod(ctx context.Context, config *AnalysisConfiguration,
|
type PodAnalyzer struct {
|
||||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
common.Analyzer ", inline"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *PodAnalyzer) Analyze() error {
|
||||||
// search all namespaces for pods that are not running
|
// search all namespaces for pods that are not running
|
||||||
list, err := client.GetClient().CoreV1().Pods(config.Namespace).List(ctx, metav1.ListOptions{})
|
list, err := a.Client.GetClient().CoreV1().Pods(a.Namespace).List(a.Context, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var preAnalysis = map[string]PreAnalysis{}
|
|
||||||
|
|
||||||
for _, pod := range list.Items {
|
for _, pod := range list.Items {
|
||||||
var failures []string
|
var failures []string
|
||||||
// Check for pending pods
|
// Check for pending pods
|
||||||
@@ -47,7 +44,7 @@ func AnalyzePod(ctx context.Context, config *AnalysisConfiguration,
|
|||||||
if containerStatus.State.Waiting.Reason == "ContainerCreating" && pod.Status.Phase == "Pending" {
|
if containerStatus.State.Waiting.Reason == "ContainerCreating" && pod.Status.Phase == "Pending" {
|
||||||
|
|
||||||
// parse the event log and append details
|
// parse the event log and append details
|
||||||
evt, err := FetchLatestPodEvent(ctx, client, &pod)
|
evt, err := common.FetchLatestPodEvent(a.Context, a.Client, &pod)
|
||||||
if err != nil || evt == nil {
|
if err != nil || evt == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -58,24 +55,27 @@ func AnalyzePod(ctx context.Context, config *AnalysisConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
preAnalysis[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = PreAnalysis{
|
a.PreAnalysis[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = common.PreAnalysis{
|
||||||
Pod: pod,
|
Pod: pod,
|
||||||
FailureDetails: failures,
|
FailureDetails: failures,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range preAnalysis {
|
for key, value := range a.PreAnalysis {
|
||||||
var currentAnalysis = Analysis{
|
var currentAnalysis = common.Result{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Name: key,
|
Name: key,
|
||||||
Error: value.FailureDetails,
|
Error: value.FailureDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, _ := util.GetParent(client, value.Pod.ObjectMeta)
|
parent, _ := util.GetParent(a.Client, value.Pod.ObjectMeta)
|
||||||
currentAnalysis.ParentObject = parent
|
currentAnalysis.ParentObject = parent
|
||||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
a.Result = append(a.Result, currentAnalysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *PodAnalyzer) GetResult() []common.Result {
|
||||||
|
return a.Result
|
||||||
|
}
|
@@ -1,24 +1,25 @@
|
|||||||
package analyzer
|
package pvc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
type PvcAnalyzer struct {
|
||||||
|
common.Analyzer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *PvcAnalyzer) Analyze() error {
|
||||||
// search all namespaces for pods that are not running
|
// search all namespaces for pods that are not running
|
||||||
list, err := client.GetClient().CoreV1().PersistentVolumeClaims(config.Namespace).List(ctx, metav1.ListOptions{})
|
list, err := a.Client.GetClient().CoreV1().PersistentVolumeClaims(a.Namespace).List(a.Context, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var preAnalysis = map[string]PreAnalysis{}
|
var preAnalysis = map[string]common.PreAnalysis{}
|
||||||
|
|
||||||
for _, pvc := range list.Items {
|
for _, pvc := range list.Items {
|
||||||
var failures []string
|
var failures []string
|
||||||
@@ -27,7 +28,7 @@ func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfigura
|
|||||||
if pvc.Status.Phase == "Pending" {
|
if pvc.Status.Phase == "Pending" {
|
||||||
|
|
||||||
// parse the event log and append details
|
// parse the event log and append details
|
||||||
evt, err := FetchLatestPvcEvent(ctx, client, &pvc)
|
evt, err := common.FetchLatestPvcEvent(a.Context, a.Client, &pvc)
|
||||||
if err != nil || evt == nil {
|
if err != nil || evt == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -36,7 +37,7 @@ func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfigura
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
preAnalysis[fmt.Sprintf("%s/%s", pvc.Namespace, pvc.Name)] = PreAnalysis{
|
preAnalysis[fmt.Sprintf("%s/%s", pvc.Namespace, pvc.Name)] = common.PreAnalysis{
|
||||||
PersistentVolumeClaim: pvc,
|
PersistentVolumeClaim: pvc,
|
||||||
FailureDetails: failures,
|
FailureDetails: failures,
|
||||||
}
|
}
|
||||||
@@ -44,16 +45,19 @@ func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfigura
|
|||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range preAnalysis {
|
for key, value := range preAnalysis {
|
||||||
var currentAnalysis = Analysis{
|
var currentAnalysis = common.Result{
|
||||||
Kind: "PersistentVolumeClaim",
|
Kind: "PersistentVolumeClaim",
|
||||||
Name: key,
|
Name: key,
|
||||||
Error: value.FailureDetails,
|
Error: value.FailureDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, _ := util.GetParent(client, value.PersistentVolumeClaim.ObjectMeta)
|
parent, _ := util.GetParent(a.Client, value.PersistentVolumeClaim.ObjectMeta)
|
||||||
currentAnalysis.ParentObject = parent
|
currentAnalysis.ParentObject = parent
|
||||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
a.Result = append(a.Result, currentAnalysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *PvcAnalyzer) GetResult() []common.Result {
|
||||||
|
return a.Result
|
||||||
|
}
|
@@ -1,25 +1,25 @@
|
|||||||
package analyzer
|
package rs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AnalyzeReplicaSet(ctx context.Context, config *AnalysisConfiguration,
|
type ReplicaSetAnalyzer struct {
|
||||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
common.Analyzer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ReplicaSetAnalyzer) Analyze() error {
|
||||||
// search all namespaces for pods that are not running
|
// search all namespaces for pods that are not running
|
||||||
list, err := client.GetClient().AppsV1().ReplicaSets(config.Namespace).List(ctx, metav1.ListOptions{})
|
list, err := a.Client.GetClient().AppsV1().ReplicaSets(a.Namespace).List(a.Context, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var preAnalysis = map[string]PreAnalysis{}
|
var preAnalysis = map[string]common.PreAnalysis{}
|
||||||
|
|
||||||
for _, rs := range list.Items {
|
for _, rs := range list.Items {
|
||||||
var failures []string
|
var failures []string
|
||||||
@@ -35,7 +35,7 @@ func AnalyzeReplicaSet(ctx context.Context, config *AnalysisConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
preAnalysis[fmt.Sprintf("%s/%s", rs.Namespace, rs.Name)] = PreAnalysis{
|
preAnalysis[fmt.Sprintf("%s/%s", rs.Namespace, rs.Name)] = common.PreAnalysis{
|
||||||
ReplicaSet: rs,
|
ReplicaSet: rs,
|
||||||
FailureDetails: failures,
|
FailureDetails: failures,
|
||||||
}
|
}
|
||||||
@@ -43,16 +43,19 @@ func AnalyzeReplicaSet(ctx context.Context, config *AnalysisConfiguration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range preAnalysis {
|
for key, value := range preAnalysis {
|
||||||
var currentAnalysis = Analysis{
|
var currentAnalysis = common.Result{
|
||||||
Kind: "ReplicaSet",
|
Kind: "ReplicaSet",
|
||||||
Name: key,
|
Name: key,
|
||||||
Error: value.FailureDetails,
|
Error: value.FailureDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, _ := util.GetParent(client, value.ReplicaSet.ObjectMeta)
|
parent, _ := util.GetParent(a.Client, value.ReplicaSet.ObjectMeta)
|
||||||
currentAnalysis.ParentObject = parent
|
currentAnalysis.ParentObject = parent
|
||||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
a.Result = append(a.Result, currentAnalysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ReplicaSetAnalyzer) GetResult() []common.Result {
|
||||||
|
return a.Result
|
||||||
|
}
|
@@ -1,33 +1,33 @@
|
|||||||
package analyzer
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AnalyzeEndpoints(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
type ServiceAnalyzer struct {
|
||||||
analysisResults *[]Analysis) error {
|
common.Analyzer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ServiceAnalyzer) Analyze() error {
|
||||||
// search all namespaces for pods that are not running
|
// search all namespaces for pods that are not running
|
||||||
list, err := client.GetClient().CoreV1().Endpoints(config.Namespace).List(ctx, metav1.ListOptions{})
|
list, err := a.Client.GetClient().CoreV1().Endpoints(a.Namespace).List(a.Context, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var preAnalysis = map[string]PreAnalysis{}
|
var preAnalysis = map[string]common.PreAnalysis{}
|
||||||
|
|
||||||
for _, ep := range list.Items {
|
for _, ep := range list.Items {
|
||||||
var failures []string
|
var failures []string
|
||||||
|
|
||||||
// Check for empty service
|
// Check for empty service
|
||||||
if len(ep.Subsets) == 0 {
|
if len(ep.Subsets) == 0 {
|
||||||
svc, err := client.GetClient().CoreV1().Services(ep.Namespace).Get(ctx, ep.Name, metav1.GetOptions{})
|
svc, err := a.Client.GetClient().CoreV1().Services(ep.Namespace).Get(a.Context, ep.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Yellow("Service %s/%s does not exist", ep.Namespace, ep.Name)
|
color.Yellow("Service %s/%s does not exist", ep.Namespace, ep.Name)
|
||||||
continue
|
continue
|
||||||
@@ -53,7 +53,7 @@ func AnalyzeEndpoints(ctx context.Context, config *AnalysisConfiguration, client
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
preAnalysis[fmt.Sprintf("%s/%s", ep.Namespace, ep.Name)] = PreAnalysis{
|
preAnalysis[fmt.Sprintf("%s/%s", ep.Namespace, ep.Name)] = common.PreAnalysis{
|
||||||
Endpoint: ep,
|
Endpoint: ep,
|
||||||
FailureDetails: failures,
|
FailureDetails: failures,
|
||||||
}
|
}
|
||||||
@@ -61,15 +61,19 @@ func AnalyzeEndpoints(ctx context.Context, config *AnalysisConfiguration, client
|
|||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range preAnalysis {
|
for key, value := range preAnalysis {
|
||||||
var currentAnalysis = Analysis{
|
var currentAnalysis = common.Result{
|
||||||
Kind: "Service",
|
Kind: "Service",
|
||||||
Name: key,
|
Name: key,
|
||||||
Error: value.FailureDetails,
|
Error: value.FailureDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, _ := util.GetParent(client, value.Endpoint.ObjectMeta)
|
parent, _ := util.GetParent(a.Client, value.Endpoint.ObjectMeta)
|
||||||
currentAnalysis.ParentObject = parent
|
currentAnalysis.ParentObject = parent
|
||||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
a.Result = append(a.Result, currentAnalysis)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ServiceAnalyzer) GetResult() []common.Result {
|
||||||
|
return a.Result
|
||||||
|
}
|
Reference in New Issue
Block a user