feat: find parent objects

Signed-off-by: Thomas Schuetz <thomas.schuetz@t-sc.eu>
This commit is contained in:
Thomas Schuetz
2023-03-25 14:25:22 +01:00
parent 36217667ce
commit b29c6e4582
4 changed files with 105 additions and 29 deletions

View File

@@ -79,8 +79,7 @@ var problemsCmd = &cobra.Command{
} }
fmt.Println(string(j)) fmt.Println(string(j))
default: default:
fmt.Printf("%s %s: %s \n%s\n", color.CyanString("%d", n), color.YellowString(analysis.Name), color.RedString(analysis.Error), color.GreenString(analysis.Details)) fmt.Printf("%s %s(%s): %s \n%s\n", color.CyanString("%d", n), color.YellowString(analysis.Name), color.CyanString(analysis.ParentObject), color.RedString(analysis.Error), color.GreenString(analysis.Details))
} }
} }

View File

@@ -1,8 +1,20 @@
package analyzer package analyzer
type Analysis struct { import (
Kind string appsv1 "k8s.io/api/apps/v1"
Name string v1 "k8s.io/api/core/v1"
Error string )
Details string
type PreAnalysis struct {
Pod v1.Pod
FailureDetails []string
ReplicaSet appsv1.ReplicaSet
}
type Analysis struct {
Kind string `json:"kind"`
Name string `json:"name"`
Error string `json:"error"`
Details string `json:"details"`
ParentObject string `json:"parentObject"`
} }

View File

@@ -22,30 +22,30 @@ func AnalyzePod(ctx context.Context, client *kubernetes.Client, aiClient ai.IAI,
if err != nil { if err != nil {
return err return err
} }
var preAnalysis = map[string]PreAnalysis{}
var brokenPods = map[string][]string{}
for _, pod := range list.Items { for _, pod := range list.Items {
var failures []string
// Check for pending pods // Check for pending pods
if pod.Status.Phase == "Pending" { if pod.Status.Phase == "Pending" {
// Check through container status to check for crashes // Check through container status to check for crashes
for _, containerStatus := range pod.Status.Conditions { for _, containerStatus := range pod.Status.Conditions {
if containerStatus.Type == "PodScheduled" && containerStatus.Reason == "Unschedulable" { if containerStatus.Type == "PodScheduled" && containerStatus.Reason == "Unschedulable" {
brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = []string{containerStatus.Message} if containerStatus.Message != "" {
failures = []string{containerStatus.Message}
}
} }
} }
} }
// Check through container status to check for crashes // Check through container status to check for crashes
var failureDetails = []string{}
for _, containerStatus := range pod.Status.ContainerStatuses { for _, containerStatus := range pod.Status.ContainerStatuses {
if containerStatus.State.Waiting != nil { if containerStatus.State.Waiting != nil {
if containerStatus.State.Waiting.Reason == "CrashLoopBackOff" || containerStatus.State.Waiting.Reason == "ImagePullBackOff" { if containerStatus.State.Waiting.Reason == "CrashLoopBackOff" || containerStatus.State.Waiting.Reason == "ImagePullBackOff" {
if containerStatus.State.Waiting.Message != "" {
failureDetails = append(failureDetails, containerStatus.State.Waiting.Message) failures = append(failures, containerStatus.State.Waiting.Message)
brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = failureDetails }
} }
// This represents a container that is still being created or blocked due to conditions such as OOMKilled // This represents a container that is still being created or blocked due to conditions such as OOMKilled
if containerStatus.State.Waiting.Reason == "ContainerCreating" && pod.Status.Phase == "Pending" { if containerStatus.State.Waiting.Reason == "ContainerCreating" && pod.Status.Phase == "Pending" {
@@ -55,24 +55,30 @@ func AnalyzePod(ctx context.Context, client *kubernetes.Client, aiClient ai.IAI,
if err != nil { if err != nil {
continue continue
} }
if evt.Reason == "FailedCreatePodSandBox" { if evt.Reason == "FailedCreatePodSandBox" && evt.Message != "" {
failureDetails = append(failureDetails, evt.Message) failures = append(failures, evt.Message)
brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = failureDetails }
}
}
}
if len(failures) > 0 {
preAnalysis[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = PreAnalysis{
Pod: pod,
FailureDetails: failures,
}
} }
} }
} for key, value := range preAnalysis {
} inputValue := strings.Join(value.FailureDetails, " ")
}
for key, value := range brokenPods {
inputValue := strings.Join(value, " ")
var currentAnalysis = Analysis{ var currentAnalysis = Analysis{
Kind: "Pod", Kind: "Pod",
Name: key, Name: key,
Error: value[0], Error: value.FailureDetails[0],
} }
parent, _ := getParent(client, value.Pod.ObjectMeta)
if explain { if explain {
s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner
s.Start() s.Start()
@@ -112,10 +118,59 @@ func AnalyzePod(ctx context.Context, client *kubernetes.Client, aiClient ai.IAI,
} }
} }
currentAnalysis.Details = response currentAnalysis.Details = response
} }
currentAnalysis.ParentObject = parent
*analysisResults = append(*analysisResults, currentAnalysis) *analysisResults = append(*analysisResults, currentAnalysis)
} }
return nil return nil
} }
func getParent(client *kubernetes.Client, meta metav1.ObjectMeta) (string, bool) {
if meta.OwnerReferences != nil {
for _, owner := range meta.OwnerReferences {
switch owner.Kind {
case "ReplicaSet":
rs, err := client.GetClient().AppsV1().ReplicaSets(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
if err != nil {
return "", false
}
if rs.OwnerReferences != nil {
return getParent(client, rs.ObjectMeta)
}
return "ReplicaSet/" + rs.Name, false
case "Deployment":
dep, err := client.GetClient().AppsV1().Deployments(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
if err != nil {
return "", false
}
if dep.OwnerReferences != nil {
return getParent(client, dep.ObjectMeta)
}
return "Deployment/" + dep.Name, false
case "StatefulSet":
sts, err := client.GetClient().AppsV1().StatefulSets(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
if err != nil {
return "", false
}
if sts.OwnerReferences != nil {
return getParent(client, sts.ObjectMeta)
}
return "StatefulSet/" + sts.Name, false
case "DaemonSet":
ds, err := client.GetClient().AppsV1().DaemonSets(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
if err != nil {
return "", false
}
if ds.OwnerReferences != nil {
return getParent(client, ds.ObjectMeta)
}
return "DaemonSet/" + ds.Name, false
}
}
}
return meta.Name, false
}

View File

@@ -23,9 +23,10 @@ func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient
return err return err
} }
var brokenRS = map[string][]string{} var preAnalysis = map[string]PreAnalysis{}
for _, rs := range list.Items { for _, rs := range list.Items {
var failures []string
// Check for empty rs // Check for empty rs
if rs.Status.Replicas == 0 { if rs.Status.Replicas == 0 {
@@ -33,24 +34,32 @@ func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient
// Check through container status to check for crashes // Check through container status to check for crashes
for _, rsStatus := range rs.Status.Conditions { for _, rsStatus := range rs.Status.Conditions {
if rsStatus.Type == "ReplicaFailure" && rsStatus.Reason == "FailedCreate" { if rsStatus.Type == "ReplicaFailure" && rsStatus.Reason == "FailedCreate" {
brokenRS[fmt.Sprintf("%s/%s", rs.Namespace, rs.Name)] = []string{rsStatus.Message} failures = []string{rsStatus.Message}
} }
} }
} }
if len(failures) > 0 {
preAnalysis[fmt.Sprintf("%s/%s", rs.Namespace, rs.Name)] = PreAnalysis{
ReplicaSet: rs,
FailureDetails: failures,
}
}
} }
for key, value := range brokenRS { for key, value := range preAnalysis {
var currentAnalysis = Analysis{ var currentAnalysis = Analysis{
Kind: "ReplicaSet", Kind: "ReplicaSet",
Name: key, Name: key,
Error: value[0], Error: value.FailureDetails[0],
} }
parent, _ := getParent(client, value.ReplicaSet.ObjectMeta)
if explain { if explain {
s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner
s.Start() s.Start()
inputValue := strings.Join(value, " ") inputValue := strings.Join(value.FailureDetails, " ")
// Check for cached data // Check for cached data
sEnc := base64.StdEncoding.EncodeToString([]byte(inputValue)) sEnc := base64.StdEncoding.EncodeToString([]byte(inputValue))
@@ -88,6 +97,7 @@ func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient
} }
currentAnalysis.Details = response currentAnalysis.Details = response
} }
currentAnalysis.ParentObject = parent
*analysisResults = append(*analysisResults, currentAnalysis) *analysisResults = append(*analysisResults, currentAnalysis)
} }