mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2025-09-05 09:12:00 +00:00
Merge pull request #221 from arbreezy/feat/statefulset-analyzer
This commit is contained in:
@@ -10,6 +10,7 @@ var coreAnalyzerMap = map[string]IAnalyzer{
|
|||||||
"PersistentVolumeClaim": PvcAnalyzer{},
|
"PersistentVolumeClaim": PvcAnalyzer{},
|
||||||
"Service": ServiceAnalyzer{},
|
"Service": ServiceAnalyzer{},
|
||||||
"Ingress": IngressAnalyzer{},
|
"Ingress": IngressAnalyzer{},
|
||||||
|
"StatefulSet": StatefulSetAnalyzer{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var additionalAnalyzerMap = map[string]IAnalyzer{
|
var additionalAnalyzerMap = map[string]IAnalyzer{
|
||||||
|
49
pkg/analyzer/statefulset.go
Normal file
49
pkg/analyzer/statefulset.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StatefulSetAnalyzer struct{}
|
||||||
|
|
||||||
|
func (StatefulSetAnalyzer) Analyze(a Analyzer) ([]Result, error) {
|
||||||
|
list, err := a.Client.GetClient().AppsV1().StatefulSets(a.Namespace).List(a.Context, metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var preAnalysis = map[string]PreAnalysis{}
|
||||||
|
|
||||||
|
for _, sts := range list.Items {
|
||||||
|
var failures []string
|
||||||
|
|
||||||
|
// get serviceName
|
||||||
|
serviceName := sts.Spec.ServiceName
|
||||||
|
_, err := a.Client.GetClient().CoreV1().Services(sts.Namespace).Get(a.Context, serviceName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
failures = append(failures, fmt.Sprintf("StatefulSet uses the service %s/%s which does not exist.", sts.Namespace, serviceName))
|
||||||
|
}
|
||||||
|
if len(failures) > 0 {
|
||||||
|
preAnalysis[fmt.Sprintf("%s/%s", sts.Namespace, sts.Name)] = PreAnalysis{
|
||||||
|
StatefulSet: sts,
|
||||||
|
FailureDetails: failures,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range preAnalysis {
|
||||||
|
var currentAnalysis = Result{
|
||||||
|
Kind: "StatefulSet",
|
||||||
|
Name: key,
|
||||||
|
Error: value.FailureDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
parent, _ := util.GetParent(a.Client, value.StatefulSet.ObjectMeta)
|
||||||
|
currentAnalysis.ParentObject = parent
|
||||||
|
a.Results = append(a.Results, currentAnalysis)
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Results, nil
|
||||||
|
}
|
78
pkg/analyzer/statefulset_test.go
Normal file
78
pkg/analyzer/statefulset_test.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||||
|
"github.com/magiconair/properties/assert"
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStatefulSetAnalyzer(t *testing.T) {
|
||||||
|
clientset := fake.NewSimpleClientset(
|
||||||
|
&appsv1.StatefulSet{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "example",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
statefulSetAnalyzer := StatefulSetAnalyzer{}
|
||||||
|
|
||||||
|
config := Analyzer{
|
||||||
|
Client: &kubernetes.Client{
|
||||||
|
Client: clientset,
|
||||||
|
},
|
||||||
|
Context: context.Background(),
|
||||||
|
Namespace: "default",
|
||||||
|
}
|
||||||
|
analysisResults, err := statefulSetAnalyzer.Analyze(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, len(analysisResults), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStatefulSetAnalyzerWithoutService(t *testing.T) {
|
||||||
|
clientset := fake.NewSimpleClientset(
|
||||||
|
&appsv1.StatefulSet{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "example",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: appsv1.StatefulSetSpec{
|
||||||
|
ServiceName: "example-svc",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
statefulSetAnalyzer := StatefulSetAnalyzer{}
|
||||||
|
|
||||||
|
config := Analyzer{
|
||||||
|
Client: &kubernetes.Client{
|
||||||
|
Client: clientset,
|
||||||
|
},
|
||||||
|
Context: context.Background(),
|
||||||
|
Namespace: "default",
|
||||||
|
}
|
||||||
|
analysisResults, err := statefulSetAnalyzer.Analyze(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
var errorFound bool
|
||||||
|
want := "StatefulSet uses the service default/example-svc which does not exist."
|
||||||
|
|
||||||
|
for _, analysis := range analysisResults {
|
||||||
|
for _, got := range analysis.Error {
|
||||||
|
if want == got {
|
||||||
|
errorFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errorFound {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !errorFound {
|
||||||
|
t.Errorf("Error expected: '%v', not found in StatefulSet's analysis results", want)
|
||||||
|
}
|
||||||
|
}
|
@@ -29,6 +29,7 @@ type PreAnalysis struct {
|
|||||||
Ingress networkv1.Ingress
|
Ingress networkv1.Ingress
|
||||||
HorizontalPodAutoscalers autov1.HorizontalPodAutoscaler
|
HorizontalPodAutoscalers autov1.HorizontalPodAutoscaler
|
||||||
PodDisruptionBudget policyv1.PodDisruptionBudget
|
PodDisruptionBudget policyv1.PodDisruptionBudget
|
||||||
|
StatefulSet appsv1.StatefulSet
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
|
Reference in New Issue
Block a user