mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2025-09-28 16:31: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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"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/schollz/progressbar/v3"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -69,75 +65,26 @@ var AnalyzeCmd = &cobra.Command{
|
||||
ctx := context.Background()
|
||||
// Get kubernetes client from viper
|
||||
client := viper.Get("kubernetesClient").(*kubernetes.Client)
|
||||
// Analysis configuration
|
||||
config := &analyzer.AnalysisConfiguration{
|
||||
// AnalysisResult configuration
|
||||
|
||||
analysis := &analysis.Analysis{
|
||||
Context: ctx,
|
||||
Namespace: namespace,
|
||||
NoCache: nocache,
|
||||
Explain: explain,
|
||||
AIClient: aiClient,
|
||||
Filters: filters,
|
||||
Client: client,
|
||||
}
|
||||
|
||||
var analysisResults *[]analyzer.Analysis = &[]analyzer.Analysis{}
|
||||
if err := analyzer.RunAnalysis(ctx, filters, config, client,
|
||||
aiClient, analysisResults); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// Run analysis
|
||||
_ = analysis.RunAnalysis()
|
||||
|
||||
if len(*analysisResults) == 0 {
|
||||
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"))
|
||||
}
|
||||
}
|
||||
analysis.PrintAnalysisResult()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
// namespace flag
|
||||
AnalyzeCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace to analyze")
|
||||
// no cache flag
|
||||
|
4
go.mod
4
go.mod
@@ -5,7 +5,6 @@ go 1.20
|
||||
require (
|
||||
github.com/fatih/color v1.15.0
|
||||
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/viper v1.15.0
|
||||
golang.org/x/term v0.6.0
|
||||
@@ -37,14 +36,11 @@ require (
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // 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/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/cast v1.5.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/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/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/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
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/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.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/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/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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/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/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/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/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
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 (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"fmt"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/hpa"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/ingress"
|
||||
"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/spf13/viper"
|
||||
)
|
||||
|
||||
var coreAnalyzerMap = map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error{
|
||||
"Pod": AnalyzePod,
|
||||
"ReplicaSet": AnalyzeReplicaSet,
|
||||
"PersistentVolumeClaim": AnalyzePersistentVolumeClaim,
|
||||
"Service": AnalyzeEndpoints,
|
||||
"Ingress": AnalyzeIngress,
|
||||
type IAnalyzer interface {
|
||||
Analyze() error
|
||||
GetResult() []common.Result
|
||||
}
|
||||
|
||||
var additionalAnalyzerMap = map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error{
|
||||
"HorizontalPodAutoScaler": AnalyzeHpa,
|
||||
const (
|
||||
PodAnalyzerName = "Pod"
|
||||
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,
|
||||
client *kubernetes.Client,
|
||||
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
|
||||
additionalAnalyzers = []string{
|
||||
HPAAnalyzerName,
|
||||
}
|
||||
}
|
||||
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
|
||||
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
|
||||
analyzerConfig.PreAnalysis = make(map[string]common.PreAnalysis)
|
||||
|
||||
switch analyzer {
|
||||
case PodAnalyzerName:
|
||||
return &pod.PodAnalyzer{
|
||||
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 {
|
||||
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 *analysis.Analysis,
|
||||
|
||||
func ParseViaAI(ctx context.Context, config *AnalysisConfiguration,
|
||||
aiClient ai.IAI, prompt []string) (string, error) {
|
||||
// parse the text with the AI backend
|
||||
inputKey := strings.Join(prompt, " ")
|
||||
@@ -103,35 +120,39 @@ func ParseViaAI(ctx context.Context, config *AnalysisConfiguration,
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
*/
|
||||
func ListFilters() ([]string, []string) {
|
||||
coreKeys := make([]string, 0, len(coreAnalyzerMap))
|
||||
for k := range coreAnalyzerMap {
|
||||
coreKeys = append(coreKeys, k)
|
||||
coreKeys := []string{}
|
||||
for _, filter := range coreAnalyzerList {
|
||||
coreKeys = append(coreKeys, filter)
|
||||
}
|
||||
|
||||
additionalKeys := make([]string, 0, len(additionalAnalyzerMap))
|
||||
for k := range additionalAnalyzerMap {
|
||||
additionalKeys = append(additionalKeys, k)
|
||||
additionalKeys := []string{}
|
||||
for _, filter := range additionalAnalyzers {
|
||||
coreKeys = append(additionalKeys, filter)
|
||||
}
|
||||
return coreKeys, additionalKeys
|
||||
}
|
||||
|
||||
func getAnalyzerMap() map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||
func GetAnalyzerList() []string {
|
||||
list := []string{}
|
||||
|
||||
mergedMap := make(map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error)
|
||||
list = append(list, coreAnalyzerList...)
|
||||
list = append(list, additionalAnalyzers...)
|
||||
|
||||
// add core analyzer
|
||||
for key, value := range coreAnalyzerMap {
|
||||
mergedMap[key] = value
|
||||
list = removeDuplicateStr(list)
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// add additional analyzer
|
||||
for key, value := range additionalAnalyzerMap {
|
||||
mergedMap[key] = value
|
||||
func removeDuplicateStr(strSlice []string) []string {
|
||||
allKeys := make(map[string]bool)
|
||||
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 (
|
||||
"context"
|
@@ -1,16 +1,28 @@
|
||||
package analyzer
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
autov1 "k8s.io/api/autoscaling/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
|
||||
NoCache bool
|
||||
Explain bool
|
||||
PreAnalysis map[string]PreAnalysis
|
||||
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 {
|
||||
@@ -19,14 +31,6 @@ type PreAnalysis struct {
|
||||
ReplicaSet appsv1.ReplicaSet
|
||||
PersistentVolumeClaim v1.PersistentVolumeClaim
|
||||
Endpoint v1.Endpoints
|
||||
Ingress networkingv1.Ingress
|
||||
HorizontalPodAutoscalers autoscalingv1.HorizontalPodAutoscaler
|
||||
}
|
||||
|
||||
type Analysis struct {
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
Error []string `json:"error"`
|
||||
Details string `json:"details"`
|
||||
ParentObject string `json:"parentObject"`
|
||||
Ingress networkv1.Ingress
|
||||
HorizontalPodAutoscalers autov1.HorizontalPodAutoscaler
|
||||
}
|
@@ -1,25 +1,22 @@
|
||||
package analyzer
|
||||
package hpa
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
||||
analysisResults *[]Analysis) error {
|
||||
type HPAAnalyzer struct {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, hpa := range list.Items {
|
||||
var failures []string
|
||||
|
||||
@@ -29,22 +26,22 @@ func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kube
|
||||
|
||||
switch scaleTargetRef.Kind {
|
||||
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 {
|
||||
scaleTargetRefNotFound = true
|
||||
}
|
||||
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 {
|
||||
scaleTargetRefNotFound = true
|
||||
}
|
||||
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 {
|
||||
scaleTargetRefNotFound = true
|
||||
}
|
||||
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 {
|
||||
scaleTargetRefNotFound = true
|
||||
}
|
||||
@@ -57,7 +54,7 @@ func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kube
|
||||
}
|
||||
|
||||
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,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
@@ -65,17 +62,20 @@ func AnalyzeHpa(ctx context.Context, config *AnalysisConfiguration, client *kube
|
||||
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
for key, value := range a.PreAnalysis {
|
||||
var currentAnalysis = common.Result{
|
||||
Kind: "HorizontalPodAutoscaler",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.Ingress.ObjectMeta)
|
||||
parent, _ := util.GetParent(a.Client, value.Ingress.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
a.Result = append(a.Result, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *HPAAnalyzer) GetResult() []common.Result {
|
||||
return a.Result
|
||||
}
|
@@ -1,25 +1,23 @@
|
||||
package analyzer
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
||||
analysisResults *[]Analysis) error {
|
||||
type IngressAnalyzer struct {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, ing := range list.Items {
|
||||
var failures []string
|
||||
|
||||
@@ -36,7 +34,7 @@ func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *
|
||||
|
||||
// check if ingressclass exist
|
||||
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 {
|
||||
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 {
|
||||
// loop over 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 {
|
||||
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 {
|
||||
_, 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 {
|
||||
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 {
|
||||
preAnalysis[fmt.Sprintf("%s/%s", ing.Namespace, ing.Name)] = PreAnalysis{
|
||||
a.PreAnalysis[fmt.Sprintf("%s/%s", ing.Namespace, ing.Name)] = common.PreAnalysis{
|
||||
Ingress: ing,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
@@ -68,17 +66,20 @@ func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *
|
||||
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
for key, value := range a.PreAnalysis {
|
||||
var currentAnalysis = common.Result{
|
||||
Kind: "Ingress",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.Ingress.ObjectMeta)
|
||||
parent, _ := util.GetParent(a.Client, value.Ingress.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
a.Result = append(a.Result, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *IngressAnalyzer) GetResult() []common.Result {
|
||||
return a.Result
|
||||
}
|
@@ -1,25 +1,22 @@
|
||||
package analyzer
|
||||
package pod
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzePod(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||
type PodAnalyzer struct {
|
||||
common.Analyzer ", inline"
|
||||
}
|
||||
|
||||
func (a *PodAnalyzer) Analyze() error {
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, pod := range list.Items {
|
||||
var failures []string
|
||||
// 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" {
|
||||
|
||||
// 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 {
|
||||
continue
|
||||
}
|
||||
@@ -58,24 +55,27 @@ func AnalyzePod(ctx context.Context, config *AnalysisConfiguration,
|
||||
}
|
||||
}
|
||||
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,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
for key, value := range a.PreAnalysis {
|
||||
var currentAnalysis = common.Result{
|
||||
Kind: "Pod",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.Pod.ObjectMeta)
|
||||
parent, _ := util.GetParent(a.Client, value.Pod.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
a.Result = append(a.Result, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PodAnalyzer) GetResult() []common.Result {
|
||||
return a.Result
|
||||
}
|
@@ -1,24 +1,25 @@
|
||||
package analyzer
|
||||
package pvc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
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
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
var preAnalysis = map[string]common.PreAnalysis{}
|
||||
|
||||
for _, pvc := range list.Items {
|
||||
var failures []string
|
||||
@@ -27,7 +28,7 @@ func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfigura
|
||||
if pvc.Status.Phase == "Pending" {
|
||||
|
||||
// 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 {
|
||||
continue
|
||||
}
|
||||
@@ -36,7 +37,7 @@ func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfigura
|
||||
}
|
||||
}
|
||||
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,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
@@ -44,16 +45,19 @@ func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfigura
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
var currentAnalysis = common.Result{
|
||||
Kind: "PersistentVolumeClaim",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.PersistentVolumeClaim.ObjectMeta)
|
||||
parent, _ := util.GetParent(a.Client, value.PersistentVolumeClaim.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
a.Result = append(a.Result, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PvcAnalyzer) GetResult() []common.Result {
|
||||
return a.Result
|
||||
}
|
@@ -1,25 +1,25 @@
|
||||
package analyzer
|
||||
package rs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzeReplicaSet(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||
type ReplicaSetAnalyzer struct {
|
||||
common.Analyzer
|
||||
}
|
||||
|
||||
func (a *ReplicaSetAnalyzer) Analyze() error {
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
var preAnalysis = map[string]common.PreAnalysis{}
|
||||
|
||||
for _, rs := range list.Items {
|
||||
var failures []string
|
||||
@@ -35,7 +35,7 @@ func AnalyzeReplicaSet(ctx context.Context, config *AnalysisConfiguration,
|
||||
}
|
||||
}
|
||||
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,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
@@ -43,16 +43,19 @@ func AnalyzeReplicaSet(ctx context.Context, config *AnalysisConfiguration,
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
var currentAnalysis = common.Result{
|
||||
Kind: "ReplicaSet",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.ReplicaSet.ObjectMeta)
|
||||
parent, _ := util.GetParent(a.Client, value.ReplicaSet.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
a.Result = append(a.Result, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ReplicaSetAnalyzer) GetResult() []common.Result {
|
||||
return a.Result
|
||||
}
|
@@ -1,33 +1,33 @@
|
||||
package analyzer
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer/common"
|
||||
|
||||
"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"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzeEndpoints(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
||||
analysisResults *[]Analysis) error {
|
||||
type ServiceAnalyzer struct {
|
||||
common.Analyzer
|
||||
}
|
||||
|
||||
func (a *ServiceAnalyzer) Analyze() error {
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
var preAnalysis = map[string]common.PreAnalysis{}
|
||||
|
||||
for _, ep := range list.Items {
|
||||
var failures []string
|
||||
|
||||
// Check for empty service
|
||||
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 {
|
||||
color.Yellow("Service %s/%s does not exist", ep.Namespace, ep.Name)
|
||||
continue
|
||||
@@ -53,7 +53,7 @@ func AnalyzeEndpoints(ctx context.Context, config *AnalysisConfiguration, client
|
||||
}
|
||||
|
||||
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,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
@@ -61,15 +61,19 @@ func AnalyzeEndpoints(ctx context.Context, config *AnalysisConfiguration, client
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
var currentAnalysis = common.Result{
|
||||
Kind: "Service",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.Endpoint.ObjectMeta)
|
||||
parent, _ := util.GetParent(a.Client, value.Endpoint.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
a.Result = append(a.Result, currentAnalysis)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ServiceAnalyzer) GetResult() []common.Result {
|
||||
return a.Result
|
||||
}
|
Reference in New Issue
Block a user