From 2dea130bde18b9e5ad9aea11c42a0d947d854548 Mon Sep 17 00:00:00 2001 From: Ruixian Song Date: Tue, 2 May 2023 13:55:06 -0700 Subject: [PATCH] Add CheckBackendConfigAnnotation rule to check-gke-ingress --- cmd/check-gke-ingress/app/ingress/rule.go | 27 ++++++++ .../app/ingress/rule_test.go | 68 +++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/cmd/check-gke-ingress/app/ingress/rule.go b/cmd/check-gke-ingress/app/ingress/rule.go index d52af04d8a..9071ca1e25 100644 --- a/cmd/check-gke-ingress/app/ingress/rule.go +++ b/cmd/check-gke-ingress/app/ingress/rule.go @@ -18,6 +18,7 @@ package ingress import ( "context" + "encoding/json" "fmt" corev1 "k8s.io/api/core/v1" @@ -25,6 +26,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clientset "k8s.io/client-go/kubernetes" "k8s.io/ingress-gce/cmd/check-gke-ingress/app/report" + "k8s.io/ingress-gce/pkg/annotations" ) func CheckServiceExistence(namespace, name string, client clientset.Interface) (*corev1.Service, string, string) { @@ -37,3 +39,28 @@ func CheckServiceExistence(namespace, name string, client clientset.Interface) ( } return svc, report.Passed, fmt.Sprintf("Service %s/%s found", namespace, name) } + +func CheckBackendConfigAnnotation(svc *corev1.Service) (*annotations.BackendConfigs, string, string) { + val, ok := getBackendConfigAnnotation(svc) + if !ok { + return nil, report.Skipped, fmt.Sprintf("Service %s/%s does not have backendconfig annotation", svc.Namespace, svc.Name) + } + beConfigs := &annotations.BackendConfigs{} + if err := json.Unmarshal([]byte(val), beConfigs); err != nil { + return nil, report.Failed, fmt.Sprintf("BackendConfig annotation is invalid in service %s/%s", svc.Namespace, svc.Name) + } + if beConfigs.Default == "" && beConfigs.Ports == nil { + return nil, report.Failed, fmt.Sprintf("BackendConfig annotation is missing both `default` and `ports` field in service %s/%s", svc.Namespace, svc.Name) + } + return beConfigs, report.Passed, fmt.Sprintf("BackendConfig annotation is valid in service %s/%s", svc.Namespace, svc.Name) +} + +func getBackendConfigAnnotation(svc *corev1.Service) (string, bool) { + for _, bcKey := range []string{annotations.BackendConfigKey, annotations.BetaBackendConfigKey} { + val, ok := svc.Annotations[bcKey] + if ok { + return val, ok + } + } + return "", false +} diff --git a/cmd/check-gke-ingress/app/ingress/rule_test.go b/cmd/check-gke-ingress/app/ingress/rule_test.go index e74f69b9ed..5e0bbbea12 100644 --- a/cmd/check-gke-ingress/app/ingress/rule_test.go +++ b/cmd/check-gke-ingress/app/ingress/rule_test.go @@ -24,6 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" "k8s.io/ingress-gce/cmd/check-gke-ingress/app/report" + "k8s.io/ingress-gce/pkg/annotations" ) func TestCheckServiceExistence(t *testing.T) { @@ -71,3 +72,70 @@ func TestCheckServiceExistence(t *testing.T) { } } } + +func TestCheckBackendConfigAnnotation(t *testing.T) { + for _, tc := range []struct { + desc string + svc corev1.Service + expect string + }{ + { + desc: "empty input", + expect: report.Skipped, + }, + { + desc: "service without beconfig annotation", + svc: corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "svc-1", + Namespace: "test", + }, + }, + expect: report.Skipped, + }, + { + desc: "service with beconfig annotation", + svc: corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "svc-1", + Namespace: "test", + Annotations: map[string]string{ + annotations.BackendConfigKey: `{"ports": {"port1": "beconfig"}}`, + }, + }, + }, + expect: report.Passed, + }, + { + desc: "service with malformed default field in beconfig annotation", + svc: corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "svc-1", + Namespace: "test", + Annotations: map[string]string{ + annotations.BackendConfigKey: `{"default": {"port1": "beconfig"}}`, + }, + }, + }, + expect: report.Failed, + }, + { + desc: "service with malformed ports field in beconfig annotation", + svc: corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "svc-1", + Namespace: "test", + Annotations: map[string]string{ + annotations.BackendConfigKey: `{"port1": "beconfig1", "port2": "beconfig2"}`, + }, + }, + }, + expect: report.Failed, + }, + } { + _, res, _ := CheckBackendConfigAnnotation(&tc.svc) + if res != tc.expect { + t.Errorf("For test case %q, expect check result = %s, but got %s", tc.desc, tc.expect, res) + } + } +}