From c8ba7d62d2f1d262263d1dff8f980e91cdcd50e8 Mon Sep 17 00:00:00 2001 From: Aris Boutselis Date: Fri, 7 Apr 2023 21:39:14 +0100 Subject: [PATCH] feat: add storage class names' check. Signed-off-by: Aris Boutselis --- pkg/analyzer/statefulset.go | 10 +++++ pkg/analyzer/statefulset_test.go | 68 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/pkg/analyzer/statefulset.go b/pkg/analyzer/statefulset.go index 1f3910a94e..155d32f806 100644 --- a/pkg/analyzer/statefulset.go +++ b/pkg/analyzer/statefulset.go @@ -25,6 +25,16 @@ func (StatefulSetAnalyzer) Analyze(a Analyzer) ([]Result, error) { if err != nil { failures = append(failures, fmt.Sprintf("StatefulSet uses the service %s/%s which does not exist.", sts.Namespace, serviceName)) } + if len(sts.Spec.VolumeClaimTemplates) > 0 { + for _, volumeClaimTemplate := range sts.Spec.VolumeClaimTemplates { + if volumeClaimTemplate.Spec.StorageClassName != nil { + _, err := a.Client.GetClient().StorageV1().StorageClasses().Get(a.Context, *volumeClaimTemplate.Spec.StorageClassName, metav1.GetOptions{}) + if err != nil { + failures = append(failures, fmt.Sprintf("StatefulSet uses the storage class %s which does not exist.", *volumeClaimTemplate.Spec.StorageClassName)) + } + } + } + } if len(failures) > 0 { preAnalysis[fmt.Sprintf("%s/%s", sts.Namespace, sts.Name)] = PreAnalysis{ StatefulSet: sts, diff --git a/pkg/analyzer/statefulset_test.go b/pkg/analyzer/statefulset_test.go index d3b3e6afa3..b00c8d0680 100644 --- a/pkg/analyzer/statefulset_test.go +++ b/pkg/analyzer/statefulset_test.go @@ -7,6 +7,8 @@ import ( "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" "github.com/magiconair/properties/assert" appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" ) @@ -76,3 +78,69 @@ func TestStatefulSetAnalyzerWithoutService(t *testing.T) { t.Errorf("Error expected: '%v', not found in StatefulSet's analysis results", want) } } + +func TestStatefulSetAnalyzerMissingStorageClass(t *testing.T) { + storageClassName := "example-sc" + clientset := fake.NewSimpleClientset( + &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example", + Namespace: "default", + }, + Spec: appsv1.StatefulSetSpec{ + ServiceName: "example-svc", + VolumeClaimTemplates: []corev1.PersistentVolumeClaim{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-example", + }, + Spec: corev1.PersistentVolumeClaimSpec{ + StorageClassName: &storageClassName, + AccessModes: []corev1.PersistentVolumeAccessMode{ + "ReadWriteOnce", + }, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), + }, + }, + }, + }, + }, + }, + }) + 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 storage class example-sc 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) + } + +}