From 2dab55746c3f0e2ea40fc8553d4cd19aa8a26c1d Mon Sep 17 00:00:00 2001 From: Ruixian Song Date: Wed, 28 Jun 2023 16:05:34 -0700 Subject: [PATCH] Add support to enable single ingress check --- cmd/check-gke-ingress/app/command/root.go | 9 +- cmd/check-gke-ingress/app/ingress/ingress.go | 23 ++- .../app/ingress/rule_test.go | 157 ++++++++++++------ 3 files changed, 129 insertions(+), 60 deletions(-) diff --git a/cmd/check-gke-ingress/app/command/root.go b/cmd/check-gke-ingress/app/command/root.go index 12f7dcba7b..14fba47fb3 100644 --- a/cmd/check-gke-ingress/app/command/root.go +++ b/cmd/check-gke-ingress/app/command/root.go @@ -48,7 +48,14 @@ var rootCmd = &cobra.Command{ fmt.Fprintf(os.Stderr, "Error connecting to Kubernetes: %v", err) os.Exit(1) } - output := ingress.CheckAllIngresses(namespace, client, beconfigClient, feConfigClient) + + var output report.Report + if len(args) == 0 { + output = ingress.CheckAllIngresses(namespace, client, beconfigClient, feConfigClient) + } else { + output = ingress.CheckIngress(args[0], namespace, client, beconfigClient, feConfigClient) + } + res, err := report.JsonReport(&output) if err != nil { fmt.Fprintf(os.Stderr, "Error processing results: %v", err) diff --git a/cmd/check-gke-ingress/app/ingress/ingress.go b/cmd/check-gke-ingress/app/ingress/ingress.go index e2ea440218..6f1d77ec2a 100644 --- a/cmd/check-gke-ingress/app/ingress/ingress.go +++ b/cmd/check-gke-ingress/app/ingress/ingress.go @@ -23,6 +23,7 @@ import ( "reflect" "runtime" + networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/ingress-gce/cmd/check-gke-ingress/app/report" @@ -31,15 +32,27 @@ import ( ) func CheckAllIngresses(namespace string, client kubernetes.Interface, beconfigClient beconfigclient.Interface, feConfigClient feconfigclient.Interface) report.Report { - output := report.Report{ - Resources: []*report.Resource{}, - } - ingressList, err := client.NetworkingV1().Ingresses(namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { fmt.Fprintf(os.Stderr, "Error listing ingresses: %v", err) os.Exit(1) } + return RunChecks(ingressList.Items, client, beconfigClient, feConfigClient) +} + +func CheckIngress(ingressName, namespace string, client kubernetes.Interface, beconfigClient beconfigclient.Interface, feConfigClient feconfigclient.Interface) report.Report { + ingress, err := client.NetworkingV1().Ingresses(namespace).Get(context.TODO(), ingressName, metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(os.Stderr, "Error getting ingress %s/%s: %v", namespace, ingressName, err) + os.Exit(1) + } + return RunChecks([]networkingv1.Ingress{*ingress}, client, beconfigClient, feConfigClient) +} + +func RunChecks(ingresses []networkingv1.Ingress, client kubernetes.Interface, beconfigClient beconfigclient.Interface, feConfigClient feconfigclient.Interface) report.Report { + output := report.Report{ + Resources: []*report.Resource{}, + } ingressChecks := []ingressCheckFunc{ CheckIngressRule, @@ -61,7 +74,7 @@ func CheckAllIngresses(namespace string, client kubernetes.Interface, beconfigCl CheckHealthCheckTimeout, } - for _, ingress := range ingressList.Items { + for _, ingress := range ingresses { // Ingress related checks ingressRes := &report.Resource{ diff --git a/cmd/check-gke-ingress/app/ingress/rule_test.go b/cmd/check-gke-ingress/app/ingress/rule_test.go index e077adfef0..6407dfb353 100644 --- a/cmd/check-gke-ingress/app/ingress/rule_test.go +++ b/cmd/check-gke-ingress/app/ingress/rule_test.go @@ -638,9 +638,8 @@ func TestCheckL7ILBNegAnnotation(t *testing.T) { } } -// TestCheckAllIngresses tests whether all the checks are triggered. -func TestCheckAllIngresses(t *testing.T) { - +// TestCheckFunctions tests CheckAllIngresses and CheckIngress. +func TestCheckFunctions(t *testing.T) { client := fake.NewSimpleClientset() beClient := fakebeconfig.NewSimpleClientset() feClient := fakefeconfig.NewSimpleClientset() @@ -749,11 +748,107 @@ func TestCheckAllIngresses(t *testing.T) { }, }, metav1.CreateOptions{}) - result := CheckAllIngresses("test", client, beClient, feClient) checkSet := make(map[string]struct{}) - for _, resource := range result.Resources { - for _, check := range resource.Checks { - checkSet[check.Name] = struct{}{} + + for _, tc := range []struct { + desc string + namespace string + ingressName string + expect report.Report + }{ + { + desc: "No ingress name specified", + namespace: "test", + ingressName: "", + expect: report.Report{ + Resources: []*report.Resource{ + { + Kind: "Ingress", + Namespace: "test", + Name: "ingress1", + Checks: []*report.Check{ + {Name: "IngressRuleCheck", Result: "PASSED"}, + {Name: "L7ILBFrontendConfigCheck", Result: "FAILED"}, + {Name: "RuleHostOverwriteCheck", Result: "PASSED"}, + {Name: "FrontenådConfigExistenceCheck", Result: "FAILED"}, + {Name: "ServiceExistenceCheck", Result: "PASSED"}, + {Name: "BackendConfigAnnotationCheck", Result: "PASSED"}, + {Name: "AppProtocolAnnotationCheck", Result: "FAILED"}, + {Name: "L7ILBNegAnnotationCheck", Result: "FAILED"}, + {Name: "BackendConfigExistenceCheck", Result: "PASSED"}, + {Name: "HealthCheckTimeoutCheck", Result: "SKIPPED"}, + }, + }, + { + Kind: "Ingress", + Namespace: "test", + Name: "ingress2", + Checks: []*report.Check{ + {Name: "IngressRuleCheck", Result: "FAILED"}, + {Name: "L7ILBFrontendConfigCheck", Result: "SKIPPED"}, + {Name: "RuleHostOverwriteCheck", Result: "FAILED"}, + {Name: "FrontendConfigExistenceCheck", Result: "PASSED"}, + {Name: "ServiceExistenceCheck", Result: "PASSED"}, + {Name: "BackendConfigAnnotationCheck", Result: "PASSED"}, + {Name: "AppProtocolAnnotationCheck", Result: "SKIPPED"}, + {Name: "L7ILBNegAnnotationCheck", Result: "SKIPPED"}, + {Name: "BackendConfigExistenceCheck", Result: "PASSED"}, + {Name: "HealthCheckTimeoutCheck", Result: "FAILED"}, + }, + }, + }, + }, + }, + { + desc: "namespace and ingress name specified", + namespace: "test", + ingressName: "ingress2", + expect: report.Report{ + Resources: []*report.Resource{ + { + Kind: "Ingress", + Namespace: "test", + Name: "ingress2", + Checks: []*report.Check{ + {Name: "IngressRuleCheck", Result: "FAILED"}, + {Name: "L7ILBFrontendConfigCheck", Result: "SKIPPED"}, + {Name: "RuleHostOverwriteCheck", Result: "FAILED"}, + {Name: "FrontendConfigExistenceCheck", Result: "PASSED"}, + {Name: "ServiceExistenceCheck", Result: "PASSED"}, + {Name: "BackendConfigAnnotationCheck", Result: "PASSED"}, + {Name: "AppProtocolAnnotationCheck", Result: "SKIPPED"}, + {Name: "L7ILBNegAnnotationCheck", Result: "SKIPPED"}, + {Name: "BackendConfigExistenceCheck", Result: "PASSED"}, + {Name: "HealthCheckTimeoutCheck", Result: "FAILED"}, + }, + }, + }, + }, + }, + } { + var result report.Report + if tc.ingressName == "" { + result = CheckAllIngresses(tc.namespace, client, beClient, feClient) + } else { + result = CheckIngress(tc.ingressName, tc.namespace, client, beClient, feClient) + } + + for _, resource := range result.Resources { + for _, check := range resource.Checks { + checkSet[check.Name] = struct{}{} + } + } + + if len(tc.expect.Resources) != len(result.Resources) { + t.Errorf("The number of ingress to be checked is not correct, want: %d, got: %d", len(tc.expect.Resources), len(result.Resources)) + } + + for i, resource := range result.Resources { + for j, check := range resource.Checks { + if diff := cmp.Diff(tc.expect.Resources[i].Checks[j].Result, check.Result); diff != "" { + t.Errorf("For ingress check %s for ingress %s/%s, (-want +got):\n%s", check.Name, resource.Namespace, resource.Name, diff) + } + } } } @@ -770,53 +865,7 @@ func TestCheckAllIngresses(t *testing.T) { L7ILBNegAnnotationCheck, } { if _, ok := checkSet[check]; !ok { - t.Errorf("Missing check %s in CheckAllIngresses", check) - } - } - - expect := report.Report{ - Resources: []*report.Resource{ - { - Kind: "Ingress", - Namespace: "test", - Name: "ingress1", - Checks: []*report.Check{ - {Name: "IngressRuleCheck", Result: "PASSED"}, - {Name: "L7ILBFrontendConfigCheck", Result: "FAILED"}, - {Name: "RuleHostOverwriteCheck", Result: "PASSED"}, - {Name: "FrontendConfigExistenceCheck", Result: "FAILED"}, - {Name: "ServiceExistenceCheck", Result: "PASSED"}, - {Name: "BackendConfigAnnotationCheck", Result: "PASSED"}, - {Name: "AppProtocolAnnotationCheck", Result: "FAILED"}, - {Name: "L7ILBNegAnnotationCheck", Result: "FAILED"}, - {Name: "BackendConfigExistenceCheck", Result: "PASSED"}, - {Name: "HealthCheckTimeoutCheck", Result: "SKIPPED"}, - }, - }, - { - Kind: "Ingress", - Namespace: "test", - Name: "ingress2", - Checks: []*report.Check{ - {Name: "IngressRuleCheck", Result: "FAILED"}, - {Name: "L7ILBFrontendConfigCheck", Result: "SKIPPED"}, - {Name: "RuleHostOverwriteCheck", Result: "FAILED"}, - {Name: "FrontendConfigExistenceCheck", Result: "PASSED"}, - {Name: "ServiceExistenceCheck", Result: "PASSED"}, - {Name: "BackendConfigAnnotationCheck", Result: "PASSED"}, - {Name: "AppProtocolAnnotationCheck", Result: "SKIPPED"}, - {Name: "L7ILBNegAnnotationCheck", Result: "SKIPPED"}, - {Name: "BackendConfigExistenceCheck", Result: "PASSED"}, - {Name: "HealthCheckTimeoutCheck", Result: "FAILED"}, - }, - }, - }, - } - for i, resource := range result.Resources { - for j, check := range resource.Checks { - if diff := cmp.Diff(expect.Resources[i].Checks[j].Result, check.Result); diff != "" { - t.Errorf("For ingress check %s for ingress %s/%s, (-want +got):\n%s", check.Name, resource.Namespace, resource.Name, diff) - } + t.Errorf("Missing check %s in check functions", check) } } }