From 8ac56e062baef2a0cf7c7ce2b4c97753f079f157 Mon Sep 17 00:00:00 2001 From: Thomas Schuetz Date: Wed, 22 Mar 2023 19:05:04 +0100 Subject: [PATCH] feat: find replicaset errors Signed-off-by: Thomas Schuetz --- pkg/analyzer/analyzer.go | 92 ++------------------------------ pkg/analyzer/podAnalyzer.go | 103 ++++++++++++++++++++++++++++++++++++ pkg/analyzer/rsAnalyzer.go | 89 +++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 88 deletions(-) create mode 100644 pkg/analyzer/podAnalyzer.go create mode 100644 pkg/analyzer/rsAnalyzer.go diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index 1e504a5ced..37b957ceef 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -2,103 +2,19 @@ package analyzer import ( "context" - "encoding/base64" - "fmt" - "strings" - "time" - - "github.com/briandowns/spinner" - "github.com/fatih/color" "github.com/k8sgpt-ai/k8sgpt/pkg/ai" "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" - "github.com/spf13/viper" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func RunAnalysis(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error { - - // search all namespaces for pods that are not running - list, err := client.GetClient().CoreV1().Pods("").List(ctx, metav1.ListOptions{}) + err := AnalyzePod(ctx, client, aiClient, explain) if err != nil { return err } - var brokenPods = map[string][]string{} - - for _, pod := range list.Items { - - // Check for pending pods - if pod.Status.Phase == "Pending" { - - // Check through container status to check for crashes - for _, containerStatus := range pod.Status.Conditions { - if containerStatus.Type == "PodScheduled" && containerStatus.Reason == "Unschedulable" { - brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = []string{containerStatus.Message} - } - } - } - - // Check through container status to check for crashes - var failureDetails = []string{} - for _, containerStatus := range pod.Status.ContainerStatuses { - if containerStatus.State.Waiting != nil { - if containerStatus.State.Waiting.Reason == "CrashLoopBackOff" || containerStatus.State.Waiting.Reason == "ImagePullBackOff" { - - failureDetails = append(failureDetails, containerStatus.State.Waiting.Message) - brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = failureDetails - } - - } - } - - } - - count := 0 - for key, value := range brokenPods { - fmt.Printf("%s: %s: %s\n", color.CyanString("%d", count), color.YellowString(key), color.RedString(value[0])) - count++ - if explain { - s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner - s.Start() - - inputValue := strings.Join(value, " ") - - // Check for cached data - sEnc := base64.StdEncoding.EncodeToString([]byte(inputValue)) - // find in viper cache - if viper.IsSet(sEnc) { - s.Stop() - // retrieve data from cache - response := viper.GetString(sEnc) - if response == "" { - color.Red("error retrieving cached data") - continue - } - output, err := base64.StdEncoding.DecodeString(response) - if err != nil { - color.Red("error decoding cached data: %v", err) - continue - } - - color.Green(string(output)) - continue - } - - response, err := aiClient.GetCompletion(ctx, inputValue) - s.Stop() - if err != nil { - color.Red("error getting completion: %v", err) - continue - } - - if !viper.IsSet(sEnc) { - viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response))) - if err := viper.WriteConfig(); err != nil { - return err - } - } - } + err = AnalyzeReplicaSet(ctx, client, aiClient, explain) + if err != nil { + return err } - return nil } diff --git a/pkg/analyzer/podAnalyzer.go b/pkg/analyzer/podAnalyzer.go new file mode 100644 index 0000000000..886f350c10 --- /dev/null +++ b/pkg/analyzer/podAnalyzer.go @@ -0,0 +1,103 @@ +package analyzer + +import ( + "context" + "encoding/base64" + "fmt" + "github.com/briandowns/spinner" + "github.com/fatih/color" + "github.com/k8sgpt-ai/k8sgpt/pkg/ai" + "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" + "github.com/spf13/viper" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "strings" + "time" +) + +func AnalyzePod(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error { + + // search all namespaces for pods that are not running + list, err := client.GetClient().CoreV1().Pods("").List(ctx, metav1.ListOptions{}) + if err != nil { + return err + } + + var brokenPods = map[string][]string{} + + for _, pod := range list.Items { + + // Check for pending pods + if pod.Status.Phase == "Pending" { + + // Check through container status to check for crashes + for _, containerStatus := range pod.Status.Conditions { + if containerStatus.Type == "PodScheduled" && containerStatus.Reason == "Unschedulable" { + brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = []string{containerStatus.Message} + } + } + } + + // Check through container status to check for crashes + var failureDetails = []string{} + for _, containerStatus := range pod.Status.ContainerStatuses { + if containerStatus.State.Waiting != nil { + if containerStatus.State.Waiting.Reason == "CrashLoopBackOff" || containerStatus.State.Waiting.Reason == "ImagePullBackOff" { + + failureDetails = append(failureDetails, containerStatus.State.Waiting.Message) + brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = failureDetails + } + + } + } + + } + + count := 0 + for key, value := range brokenPods { + fmt.Printf("%s: %s: %s\n", color.CyanString("%d", count), color.YellowString(key), color.RedString(value[0])) + count++ + if explain { + s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner + s.Start() + + inputValue := strings.Join(value, " ") + + // Check for cached data + sEnc := base64.StdEncoding.EncodeToString([]byte(inputValue)) + // find in viper cache + if viper.IsSet(sEnc) { + s.Stop() + // retrieve data from cache + response := viper.GetString(sEnc) + if response == "" { + color.Red("error retrieving cached data") + continue + } + output, err := base64.StdEncoding.DecodeString(response) + if err != nil { + color.Red("error decoding cached data: %v", err) + continue + } + + color.Green(string(output)) + continue + } + + response, err := aiClient.GetCompletion(ctx, inputValue) + s.Stop() + if err != nil { + color.Red("error getting completion: %v", err) + continue + } + + if !viper.IsSet(sEnc) { + viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response))) + if err := viper.WriteConfig(); err != nil { + return err + } + } + } + } + + return nil +} diff --git a/pkg/analyzer/rsAnalyzer.go b/pkg/analyzer/rsAnalyzer.go new file mode 100644 index 0000000000..2841da281c --- /dev/null +++ b/pkg/analyzer/rsAnalyzer.go @@ -0,0 +1,89 @@ +package analyzer + +import ( + "context" + "encoding/base64" + "fmt" + "github.com/briandowns/spinner" + "github.com/fatih/color" + "github.com/k8sgpt-ai/k8sgpt/pkg/ai" + "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" + "github.com/spf13/viper" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "strings" + "time" +) + +func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error { + + // search all namespaces for pods that are not running + list, err := client.GetClient().AppsV1().ReplicaSets("").List(ctx, metav1.ListOptions{}) + if err != nil { + return err + } + + var brokenRS = map[string][]string{} + + for _, rs := range list.Items { + + // Check for empty rs + if rs.Status.Replicas == 0 { + + // Check through container status to check for crashes + for _, rsStatus := range rs.Status.Conditions { + if rsStatus.Type == "ReplicaFailure" && rsStatus.Reason == "FailedCreate" { + brokenRS[fmt.Sprintf("%s/%s", rs.Namespace, rs.Name)] = []string{rsStatus.Message} + } + } + } + } + + count := 0 + for key, value := range brokenRS { + fmt.Printf("%s: %s: %s\n", color.CyanString("%d", count), color.YellowString(key), color.RedString(value[0])) + count++ + if explain { + s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner + s.Start() + + inputValue := strings.Join(value, " ") + + // Check for cached data + sEnc := base64.StdEncoding.EncodeToString([]byte(inputValue)) + // find in viper cache + if viper.IsSet(sEnc) { + s.Stop() + // retrieve data from cache + response := viper.GetString(sEnc) + if response == "" { + color.Red("error retrieving cached data") + continue + } + output, err := base64.StdEncoding.DecodeString(response) + if err != nil { + color.Red("error decoding cached data: %v", err) + continue + } + + color.Green(string(output)) + continue + } + + response, err := aiClient.GetCompletion(ctx, inputValue) + s.Stop() + if err != nil { + color.Red("error getting completion: %v", err) + continue + } + + if !viper.IsSet(sEnc) { + viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response))) + if err := viper.WriteConfig(); err != nil { + return err + } + } + } + } + + return nil +}