From 888c4ecc652c8323bf44eca521edc89b9e369e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Sun, 12 Feb 2023 12:06:50 +0100 Subject: [PATCH 1/4] wip --- internal/adminapi/kong.go | 2 +- internal/controllers/gateway/route_utils.go | 2 +- internal/dataplane/kong_client.go | 10 +- internal/dataplane/kong_client_test.go | 3 + internal/dataplane/kongstate/util_test.go | 6 + .../parser/ingressclassparemeters_test.go | 17 ++- .../dataplane/parser/ingressrules_test.go | 6 + internal/dataplane/parser/parser.go | 13 +- internal/dataplane/parser/parser_test.go | 99 +++++++------ .../dataplane/parser/translate_ingress.go | 13 +- .../parser/translate_ingress_test.go | 45 +++--- .../dataplane/parser/translate_knative.go | 3 +- internal/manager/run.go | 1 + internal/store/fake_store.go | 44 +++++- internal/store/fake_store_test.go | 17 ++- internal/store/store.go | 139 +++++++++--------- internal/store/store_test.go | 8 +- 17 files changed, 250 insertions(+), 178 deletions(-) diff --git a/internal/adminapi/kong.go b/internal/adminapi/kong.go index 7498877f78..1c263db0d3 100644 --- a/internal/adminapi/kong.go +++ b/internal/adminapi/kong.go @@ -78,7 +78,7 @@ func MakeHTTPClient(opts *HTTPClientOpts, kongAdminToken string) (*http.Client, var tlsConfig tls.Config if opts.TLSSkipVerify { - tlsConfig.InsecureSkipVerify = true //nolint:gosec + tlsConfig.InsecureSkipVerify = true } if opts.TLSServerName != "" { diff --git a/internal/controllers/gateway/route_utils.go b/internal/controllers/gateway/route_utils.go index 746ce009d5..c119b288b5 100644 --- a/internal/controllers/gateway/route_utils.go +++ b/internal/controllers/gateway/route_utils.go @@ -227,7 +227,7 @@ func getSupportedGatewayForRoute[T types.RouteT](ctx context.Context, mgrc clien // - And finally check if that listeners is marked as Ready. if err := existsMatchingReadyListenerInStatus(route, listener, gateway.Status.Listeners); err != nil { continue - } else { //nolint:revive + } else { allowedBySupportedKinds = true } diff --git a/internal/dataplane/kong_client.go b/internal/dataplane/kong_client.go index e7295b3f59..835a815253 100644 --- a/internal/dataplane/kong_client.go +++ b/internal/dataplane/kong_client.go @@ -57,6 +57,8 @@ type AdminAPIClientsProvider interface { type KongClient struct { logger logrus.FieldLogger + client client.Client + // ingressClass indicates the Kubernetes ingress class that should be // used to qualify support for any given Kubernetes object to be parsed // into data-plane configuration. @@ -148,12 +150,13 @@ func NewKongClient( kongConfig sendconfig.Config, eventRecorder record.EventRecorder, dbMode string, + client client.Client, clientsProvider AdminAPIClientsProvider, updateStrategyResolver sendconfig.UpdateStrategyResolver, configChangeDetector sendconfig.ConfigurationChangeDetector, ) (*KongClient, error) { // build the client object - cache := store.NewCacheStores() + cache := store.NewCacheStores(client) c := &KongClient{ logger: logger, ingressClass: ingressClass, @@ -161,6 +164,7 @@ func NewKongClient( diagnostic: diagnostic, prometheusMetrics: metrics.NewCtrlFuncMetrics(), cache: &cache, + client: client, kongConfig: kongConfig, eventRecorder: eventRecorder, dbmode: dbMode, @@ -389,7 +393,7 @@ func (c *KongClient) Update(ctx context.Context) error { defer c.lock.Unlock() // build the kongstate object from the Kubernetes objects in the storer - storer := store.New(*c.cache, c.ingressClass, c.logger) + storer := store.New(c.client, *c.cache, c.ingressClass, c.logger) // initialize a parser c.logger.Debug("parsing kubernetes objects into data-plane configuration") @@ -412,7 +416,7 @@ func (c *KongClient) Update(ctx context.Context) error { } // parse the Kubernetes objects from the storer into Kong configuration - kongstate, translationFailures := p.Build() + kongstate, translationFailures := p.Build(ctx) if failuresCount := len(translationFailures); failuresCount > 0 { c.prometheusMetrics.RecordTranslationFailure() c.recordResourceFailureEvents(translationFailures, KongConfigurationTranslationFailedEventReason) diff --git a/internal/dataplane/kong_client_test.go b/internal/dataplane/kong_client_test.go index c34b5799e0..3e9ea8fc57 100644 --- a/internal/dataplane/kong_client_test.go +++ b/internal/dataplane/kong_client_test.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" + ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/adminapi" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane" @@ -424,6 +425,7 @@ func setupTestKongClient( config := sendconfig.Config{} eventRecorder := record.NewFakeRecorder(0) dbMode := "off" + client := ctrlfake.NewClientBuilder().Build() kongClient, err := dataplane.NewKongClient( logger, @@ -433,6 +435,7 @@ func setupTestKongClient( config, eventRecorder, dbMode, + client, clientsProvider, updateStrategyResolver, configChangeDetector, diff --git a/internal/dataplane/kongstate/util_test.go b/internal/dataplane/kongstate/util_test.go index 1c2d2e3e82..7723e64428 100644 --- a/internal/dataplane/kongstate/util_test.go +++ b/internal/dataplane/kongstate/util_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/kong/go-kong/kong" + "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" @@ -372,6 +373,8 @@ func TestGetKongIngressForServices(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress2", Namespace: corev1.NamespaceDefault, + // https://github.com/kubernetes-sigs/controller-runtime/blob/22718275bffe3185276dc835d610c658f06dac07/pkg/client/fake/client.go#L247-L250 + ResourceVersion: "999", }, }, }, @@ -430,6 +433,8 @@ func TestGetKongIngressForServices(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress2", Namespace: corev1.NamespaceDefault, + // https://github.com/kubernetes-sigs/controller-runtime/blob/22718275bffe3185276dc835d610c658f06dac07/pkg/client/fake/client.go#L247-L250 + ResourceVersion: "999", }, }, }, @@ -437,6 +442,7 @@ func TestGetKongIngressForServices(t *testing.T) { t.Run(tt.name, func(t *testing.T) { storer, err := store.NewFakeStore(store.FakeObjects{ KongIngresses: tt.kongIngresses, + Services: lo.Values(tt.services), }) require.NoError(t, err) diff --git a/internal/dataplane/parser/ingressclassparemeters_test.go b/internal/dataplane/parser/ingressclassparemeters_test.go index d2e5e4e5de..a48d080b51 100644 --- a/internal/dataplane/parser/ingressclassparemeters_test.go +++ b/internal/dataplane/parser/ingressclassparemeters_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "errors" "fmt" "reflect" @@ -11,6 +12,7 @@ import ( "github.com/stretchr/testify/require" netv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" configurationv1alpha1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1alpha1" @@ -129,6 +131,10 @@ func TestGetIngressClassParameters(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { ingressClass := &netv1.IngressClass{ + TypeMeta: metav1.TypeMeta{ + Kind: "IngressClass", + APIVersion: "networking.k8s.io/v1", + }, ObjectMeta: metav1.ObjectMeta{ Namespace: testNamespaceName, Name: tc.name, @@ -137,14 +143,19 @@ func TestGetIngressClassParameters(t *testing.T) { Parameters: tc.paramRef, }, } - cacheStores, err := store.NewCacheStoresFromObjs() + client := ctrlfake.NewClientBuilder(). + WithObjects( + ingressClass, + ). + Build() + cacheStores, err := store.NewCacheStoresFromObjs(client, ingressClass, icp) // TODO(pmalek) require.NoError(t, err) err = cacheStores.Add(ingressClass) require.NoError(t, err) err = cacheStores.Add(icp) require.NoError(t, err) - s := store.New(cacheStores, ingressClass.Name, logrus.New()) - icpSpec, err := getIngressClassParametersOrDefault(s) + s := store.New(client, cacheStores, ingressClass.Name, logrus.New()) // TODO(pmalek) + icpSpec, err := getIngressClassParametersOrDefault(context.TODO(), s) assert.Truef(t, reflect.DeepEqual(*tc.parameterSpec, icpSpec), fmt.Sprintf("should get same ingress parameter spec: expected %+v, actual %+v", tc.parameterSpec, icpSpec), ) diff --git a/internal/dataplane/parser/ingressrules_test.go b/internal/dataplane/parser/ingressrules_test.go index 998033b692..afd7d49414 100644 --- a/internal/dataplane/parser/ingressrules_test.go +++ b/internal/dataplane/parser/ingressrules_test.go @@ -292,6 +292,8 @@ func TestGetK8sServicesForBackends(t *testing.T) { Annotations: map[string]string{ "konghq.com/foo": "bar", }, + // https://github.com/kubernetes-sigs/controller-runtime/blob/22718275bffe3185276dc835d610c658f06dac07/pkg/client/fake/client.go#L247-L250 + ResourceVersion: "999", }, }, { @@ -301,6 +303,8 @@ func TestGetK8sServicesForBackends(t *testing.T) { Annotations: map[string]string{ "konghq.com/foo": "baz", }, + // https://github.com/kubernetes-sigs/controller-runtime/blob/22718275bffe3185276dc835d610c658f06dac07/pkg/client/fake/client.go#L247-L250 + ResourceVersion: "999", }, }, }, @@ -329,6 +333,8 @@ func TestGetK8sServicesForBackends(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "test-service1", Namespace: corev1.NamespaceDefault, + // https://github.com/kubernetes-sigs/controller-runtime/blob/22718275bffe3185276dc835d610c658f06dac07/pkg/client/fake/client.go#L247-L250 + ResourceVersion: "999", }, }}, expectedAnnotations: map[string]string{}, diff --git a/internal/dataplane/parser/parser.go b/internal/dataplane/parser/parser.go index 6bb5e7ba51..537eadd0c6 100644 --- a/internal/dataplane/parser/parser.go +++ b/internal/dataplane/parser/parser.go @@ -2,6 +2,7 @@ package parser import ( "bytes" + "context" "crypto/tls" "fmt" "reflect" @@ -79,11 +80,11 @@ func NewParser( // Build creates a Kong configuration from Ingress and Custom resources // defined in Kubernetes. It returns a slice of ResourceFailures which should // be used to provide users with feedback on Kubernetes objects validity. -func (p *Parser) Build() (*kongstate.KongState, []failures.ResourceFailure) { +func (p *Parser) Build(ctx context.Context) (*kongstate.KongState, []failures.ResourceFailure) { // parse and merge all rules together from all Kubernetes API sources ingressRules := mergeIngressRules( - p.ingressRulesFromIngressV1beta1(), - p.ingressRulesFromIngressV1(), + p.ingressRulesFromIngressV1beta1(ctx), + p.ingressRulesFromIngressV1(ctx), p.ingressRulesFromTCPIngressV1beta1(), p.ingressRulesFromUDPIngressV1beta1(), p.ingressRulesFromKnativeIngress(), @@ -590,7 +591,7 @@ func getServiceEndpoints( // Check if the service is an upstream service through Ingress Class parameters. var isSvcUpstream bool - ingressClassParameters, err := getIngressClassParametersOrDefault(s) + ingressClassParameters, err := getIngressClassParametersOrDefault(context.TODO(), s) if err != nil { log.Debugf("error getting an IngressClassParameters: %v", err) } else { @@ -615,9 +616,9 @@ func getServiceEndpoints( // getIngressClassParametersOrDefault returns the parameters for the current ingress class. // If the cluster operators have specified a set of parameters explicitly, it returns those. // Otherwise, it returns a default set of parameters. -func getIngressClassParametersOrDefault(s store.Storer) (configurationv1alpha1.IngressClassParametersSpec, error) { +func getIngressClassParametersOrDefault(ctx context.Context, s store.Storer) (configurationv1alpha1.IngressClassParametersSpec, error) { ingressClassName := s.GetIngressClassName() - ingressClass, err := s.GetIngressClassV1(ingressClassName) + ingressClass, err := s.GetIngressClassV1(ctx, ingressClassName) if err != nil { return configurationv1alpha1.IngressClassParametersSpec{}, err } diff --git a/internal/dataplane/parser/parser_test.go b/internal/dataplane/parser/parser_test.go index 75cc7750f2..1481ae7cab 100644 --- a/internal/dataplane/parser/parser_test.go +++ b/internal/dataplane/parser/parser_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" "reflect" "sort" @@ -282,7 +283,7 @@ func TestGlobalPlugin(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Plugins), @@ -464,7 +465,7 @@ func TestSecretConfigurationPlugin(t *testing.T) { store, err := store.NewFakeStore(objects) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.Nil(err) assert.NotNil(state) @@ -570,7 +571,7 @@ func TestSecretConfigurationPlugin(t *testing.T) { store, err := store.NewFakeStore(objects) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.Nil(err) assert.NotNil(state) @@ -673,7 +674,7 @@ func TestSecretConfigurationPlugin(t *testing.T) { store, err := store.NewFakeStore(objects) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(0, len(state.Plugins), @@ -725,7 +726,7 @@ func TestSecretConfigurationPlugin(t *testing.T) { store, err := store.NewFakeStore(objects) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) for _, testcase := range references { @@ -824,7 +825,7 @@ func TestSecretConfigurationPlugin(t *testing.T) { store, err := store.NewFakeStore(objects) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(0, len(state.Plugins), @@ -860,7 +861,7 @@ func TestCACertificate(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -915,7 +916,7 @@ func TestCACertificate(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -998,7 +999,7 @@ func TestCACertificate(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) assert.Len(translationFailures, 3) assert.NotNil(state) @@ -1084,7 +1085,7 @@ func TestServiceClientCertificate(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Certificates), @@ -1153,7 +1154,7 @@ func TestServiceClientCertificate(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Len(t, translationFailures, 1) assert.NotNil(state) assert.Equal(0, len(state.Certificates), @@ -1214,7 +1215,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1298,7 +1299,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1383,7 +1384,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1469,7 +1470,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1554,7 +1555,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1639,7 +1640,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1724,7 +1725,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1809,7 +1810,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1894,7 +1895,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -1977,7 +1978,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2060,7 +2061,7 @@ func TestKongRouteAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2121,7 +2122,7 @@ func TestKongProcessClasslessIngress(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2172,7 +2173,7 @@ func TestKongProcessClasslessIngress(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2250,7 +2251,7 @@ func TestKnativeIngressAndPlugins(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2329,7 +2330,7 @@ func TestKnativeIngressAndPlugins(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2399,7 +2400,7 @@ func TestKnativeIngressAndPlugins(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2485,7 +2486,7 @@ func TestKnativeIngressAndPlugins(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2602,7 +2603,7 @@ func TestKongServiceAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2689,7 +2690,7 @@ func TestKongServiceAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2784,7 +2785,7 @@ func TestKongServiceAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) @@ -2858,7 +2859,7 @@ func TestDefaultBackend(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Services), @@ -2928,7 +2929,7 @@ func TestDefaultBackend(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Len(t, translationFailures, 1) assert.NotNil(state) assert.Equal(0, len(state.Certificates), @@ -2994,7 +2995,7 @@ func TestParserSecret(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(0, len(state.Certificates), @@ -3076,7 +3077,7 @@ func TestParserSecret(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Certificates), @@ -3205,7 +3206,7 @@ func TestParserSecret(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Certificates), @@ -3289,7 +3290,7 @@ func TestParserSecret(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Certificates), @@ -3372,7 +3373,7 @@ func TestParserSNI(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) // parser tests do not check tags, these are tested independently @@ -3440,7 +3441,7 @@ func TestParserSNI(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) // parser tests do not check tags, these are tested independently @@ -3502,7 +3503,7 @@ func TestParserHostAliases(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) // parser tests do not check tags, these are tested independently @@ -3557,7 +3558,7 @@ func TestParserHostAliases(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) // parser tests do not check tags, these are tested independently @@ -3613,7 +3614,7 @@ func TestParserHostAliases(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) // parser tests do not check tags, these are tested independently @@ -3705,7 +3706,7 @@ func TestPluginAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Plugins), @@ -3805,7 +3806,7 @@ func TestPluginAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Plugins), @@ -3876,7 +3877,7 @@ func TestPluginAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Plugins), @@ -3923,7 +3924,7 @@ func TestPluginAnnotations(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(0, len(state.Plugins), @@ -4706,7 +4707,7 @@ func TestPickPort(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.Equal(tt.wantTarget, *state.Upstreams[0].Targets[0].Target.Target) @@ -4825,7 +4826,7 @@ func TestCertificate(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(3, len(state.Certificates)) @@ -4918,7 +4919,7 @@ func TestCertificate(t *testing.T) { }) assert.Nil(err) p := mustNewParser(t, store) - state, translationFailures := p.Build() + state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) assert.Equal(1, len(state.Certificates)) diff --git a/internal/dataplane/parser/translate_ingress.go b/internal/dataplane/parser/translate_ingress.go index e9d901e9fc..00c7194fcf 100644 --- a/internal/dataplane/parser/translate_ingress.go +++ b/internal/dataplane/parser/translate_ingress.go @@ -1,6 +1,7 @@ package parser import ( + "context" "errors" "fmt" "sort" @@ -29,11 +30,11 @@ var priorityForPath = map[netv1.PathType]int{ netv1.PathTypeImplementationSpecific: 100, } -func (p *Parser) ingressRulesFromIngressV1beta1() ingressRules { +func (p *Parser) ingressRulesFromIngressV1beta1(ctx context.Context) ingressRules { result := newIngressRules() - ingressList := p.storer.ListIngressesV1beta1() - icp, err := getIngressClassParametersOrDefault(p.storer) + ingressList := p.storer.ListIngressesV1beta1(ctx) + icp, err := getIngressClassParametersOrDefault(ctx, p.storer) if err != nil { if !errors.As(err, &store.ErrNotFound{}) { // anything else is unexpected @@ -187,11 +188,11 @@ func (p *Parser) ingressRulesFromIngressV1beta1() ingressRules { return result } -func (p *Parser) ingressRulesFromIngressV1() ingressRules { +func (p *Parser) ingressRulesFromIngressV1(ctx context.Context) ingressRules { result := newIngressRules() - ingressList := p.storer.ListIngressesV1() - icp, err := getIngressClassParametersOrDefault(p.storer) + ingressList := p.storer.ListIngressesV1(ctx) + icp, err := getIngressClassParametersOrDefault(ctx, p.storer) if err != nil { if !errors.As(err, &store.ErrNotFound{}) { // anything else is unexpected diff --git a/internal/dataplane/parser/translate_ingress_test.go b/internal/dataplane/parser/translate_ingress_test.go index f5a11ce9eb..0efc126f62 100644 --- a/internal/dataplane/parser/translate_ingress_test.go +++ b/internal/dataplane/parser/translate_ingress_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -272,7 +273,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal(ingressRules{ ServiceNameToServices: make(map[string]kongstate.Service), ServiceNameToParent: make(map[string]client.Object), @@ -288,7 +289,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) assert.Equal("foo-svc.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Host) assert.Equal(80, *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Port) @@ -303,7 +304,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal(2, len(parsedInfo.ServiceNameToServices)) assert.Equal("foo-svc.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Host) assert.Equal(80, *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Port) @@ -324,7 +325,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("bar-namespace/sooper-secret"))) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("bar-namespace/sooper-secret2"))) }) @@ -337,7 +338,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) assert.Equal("cert-manager-solver-pod.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.cert-manager-solver-pod.80"].Host) @@ -358,7 +359,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal("/", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Routes[0].Paths[0]) assert.Equal("example.com", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Routes[0].Hosts[0]) }) @@ -372,7 +373,7 @@ func TestFromIngressV1beta1(t *testing.T) { p := mustNewParser(t, store) assert.NotPanics(func() { - p.ingressRulesFromIngressV1beta1() + p.ingressRulesFromIngressV1beta1(context.TODO()) }) }) t.Run("Ingress rules with multiple ports for one Service use separate hostnames for each port", func(t *testing.T) { @@ -384,7 +385,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal("foo-svc.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Host) assert.Equal("foo-svc.foo-namespace.8000.svc", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.8000"].Host) }) @@ -397,7 +398,7 @@ func TestFromIngressV1beta1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1beta1() + parsedInfo := p.ingressRulesFromIngressV1beta1(context.TODO()) assert.Equal(translators.KongPathRegexPrefix+"/foo/\\d{3}", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.80"].Routes[0].Paths[0]) }) } @@ -746,7 +747,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal(ingressRules{ ServiceNameToServices: make(map[string]kongstate.Service), ServiceNameToParent: make(map[string]client.Object), @@ -762,7 +763,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) assert.Equal("foo-svc.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Host) assert.Equal(80, *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Port) @@ -780,15 +781,15 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() - assert.Equal(2, len(parsedInfo.ServiceNameToServices)) + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) + require.Len(t, parsedInfo.ServiceNameToServices, 2) assert.Equal("foo-svc.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Host) assert.Equal(80, *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Port) assert.Equal("/", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Routes[0].Paths[0]) assert.Equal("example.com", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Routes[0].Hosts[0]) - assert.Equal(1, len(parsedInfo.ServiceNameToServices["bar-namespace.default-svc.80"].Routes)) + require.Len(t, parsedInfo.ServiceNameToServices["bar-namespace.default-svc.80"].Routes, 1) assert.Equal("/", *parsedInfo.ServiceNameToServices["bar-namespace.default-svc.80"].Routes[0].Paths[0]) assert.Equal(0, len(parsedInfo.ServiceNameToServices["bar-namespace.default-svc.80"].Routes[0].Hosts)) }) @@ -801,7 +802,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("bar-namespace/sooper-secret"))) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("bar-namespace/sooper-secret2"))) }) @@ -814,7 +815,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) assert.Equal("cert-manager-solver-pod.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.cert-manager-solver-pod.pnum-80"].Host) @@ -835,7 +836,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal("/", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Routes[0].Paths[0]) assert.Equal("example.com", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Routes[0].Hosts[0]) }) @@ -849,7 +850,7 @@ func TestFromIngressV1(t *testing.T) { p := mustNewParser(t, store) assert.NotPanics(func() { - p.ingressRulesFromIngressV1() + p.ingressRulesFromIngressV1(context.TODO()) }) }) t.Run("Ingress rules with multiple ports for one Service use separate hostnames for each port", func(t *testing.T) { @@ -861,7 +862,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal("foo-svc.foo-namespace.80.svc", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Host) assert.Equal("foo-svc.foo-namespace.8000.svc", @@ -876,7 +877,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) _, ok := parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"] assert.True(ok) }) @@ -889,7 +890,7 @@ func TestFromIngressV1(t *testing.T) { require.NoError(t, err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal(translators.KongPathRegexPrefix+"/foo/\\d{3}", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Routes[0].Paths[0]) }) } @@ -943,7 +944,7 @@ func TestFromIngressV1_RegexPrefix(t *testing.T) { p.EnableRegexPathPrefix() - parsedInfo := p.ingressRulesFromIngressV1() + parsedInfo := p.ingressRulesFromIngressV1(context.TODO()) assert.Equal("~/whatever$", *parsedInfo.ServiceNameToServices["foo-namespace.foo-svc.pnum-80"].Routes[0].Paths[0]) }) } diff --git a/internal/dataplane/parser/translate_knative.go b/internal/dataplane/parser/translate_knative.go index 94e7dca418..50805c44b4 100644 --- a/internal/dataplane/parser/translate_knative.go +++ b/internal/dataplane/parser/translate_knative.go @@ -1,6 +1,7 @@ package parser import ( + "context" "errors" "fmt" "sort" @@ -22,7 +23,7 @@ func (p *Parser) ingressRulesFromKnativeIngress() ingressRules { // not a resource specific to Knative. However, the reason we're using it (enabling the 2.x regex heuristic) is // Kong-specific, so in absence of a proper Knative IngressClass to attach our IngressClassParams to, we may as // well use the stock Kubernetes resource. - icp, err := getIngressClassParametersOrDefault(p.storer) + icp, err := getIngressClassParametersOrDefault(context.TODO(), p.storer) if err != nil { if !errors.As(err, &store.ErrNotFound{}) { // anything else is unexpected diff --git a/internal/manager/run.go b/internal/manager/run.go index a066bbcf47..3cfb1ffe95 100644 --- a/internal/manager/run.go +++ b/internal/manager/run.go @@ -137,6 +137,7 @@ func Run(ctx context.Context, c *Config, diagnostic util.ConfigDumpDiagnostic, d kongConfig, eventRecorder, dbMode, + mgr.GetClient(), clientsManager, updateStrategyResolver, configurationChangeDetector, diff --git a/internal/store/fake_store.go b/internal/store/fake_store.go index 518117bcc8..8944291d65 100644 --- a/internal/store/fake_store.go +++ b/internal/store/fake_store.go @@ -9,10 +9,13 @@ import ( netv1beta1 "k8s.io/api/networking/v1beta1" "k8s.io/client-go/tools/cache" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" + "github.com/kong/kubernetes-ingress-controller/v2/internal/manager/featuregates" + "github.com/kong/kubernetes-ingress-controller/v2/internal/manager/scheme" configurationv1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" configurationv1alpha1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1alpha1" configurationv1beta1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1beta1" @@ -60,7 +63,17 @@ type FakeObjects struct { func NewFakeStore( objects FakeObjects, ) (Storer, error) { - var s Storer + fg := featuregates.GetFeatureGatesDefaults() + fg[featuregates.KnativeFeature] = true + fg[featuregates.GatewayAlphaFeature] = true + + scheme, err := scheme.Get(fg) + if err != nil { + return nil, err + } + + clientBuilder := ctrlclientfake.NewClientBuilder(). + WithScheme(scheme) ingressV1beta1Store := cache.NewStore(keyFunc) for _, ingress := range objects.IngressesV1beta1 { @@ -68,6 +81,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(ingress) } ingressV1Store := cache.NewStore(keyFunc) for _, ingress := range objects.IngressesV1 { @@ -75,6 +89,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(ingress) } ingressClassV1Store := cache.NewStore(clusterResourceKeyFunc) for _, ingress := range objects.IngressClassesV1 { @@ -82,6 +97,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(ingress) } IngressClassParametersV1alpha1Store := cache.NewStore(clusterResourceKeyFunc) for _, IngressClassParametersV1alpha1 := range objects.IngressClassParametersV1alpha1 { @@ -89,30 +105,35 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(IngressClassParametersV1alpha1) } httprouteStore := cache.NewStore(keyFunc) for _, httproute := range objects.HTTPRoutes { if err := httprouteStore.Add(httproute); err != nil { return nil, err } + clientBuilder.WithObjects(httproute) } udprouteStore := cache.NewStore(keyFunc) for _, udproute := range objects.UDPRoutes { if err := udprouteStore.Add(udproute); err != nil { return nil, err } + clientBuilder.WithObjects(udproute) } tcprouteStore := cache.NewStore(keyFunc) for _, tcproute := range objects.TCPRoutes { if err := tcprouteStore.Add(tcproute); err != nil { return nil, err } + clientBuilder.WithObjects(tcproute) } tlsrouteStore := cache.NewStore(keyFunc) for _, tlsroute := range objects.TLSRoutes { if err := tlsrouteStore.Add(tlsroute); err != nil { return nil, err } + clientBuilder.WithObjects(tlsroute) } grpcrouteStore := cache.NewStore(keyFunc) for _, grpcroute := range objects.GRPCRoutes { @@ -125,12 +146,14 @@ func NewFakeStore( if err := referencegrantStore.Add(referencegrant); err != nil { return nil, err } + clientBuilder.WithObjects(referencegrant) } gatewayStore := cache.NewStore(keyFunc) for _, gw := range objects.Gateways { if err := gatewayStore.Add(gw); err != nil { return nil, err } + clientBuilder.WithObjects(gw) } tcpIngressStore := cache.NewStore(keyFunc) for _, ingress := range objects.TCPIngresses { @@ -138,12 +161,14 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(ingress) } udpIngressStore := cache.NewStore(keyFunc) for _, ingress := range objects.UDPIngresses { if err := udpIngressStore.Add(ingress); err != nil { return nil, err } + clientBuilder.WithObjects(ingress) } serviceStore := cache.NewStore(keyFunc) for _, s := range objects.Services { @@ -151,6 +176,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(s) } secretsStore := cache.NewStore(keyFunc) for _, s := range objects.Secrets { @@ -158,6 +184,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(s) } endpointStore := cache.NewStore(keyFunc) for _, e := range objects.Endpoints { @@ -165,6 +192,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(e) } kongIngressStore := cache.NewStore(keyFunc) for _, k := range objects.KongIngresses { @@ -172,6 +200,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(k) } consumerStore := cache.NewStore(keyFunc) for _, c := range objects.KongConsumers { @@ -179,6 +208,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(c) } kongPluginsStore := cache.NewStore(keyFunc) for _, p := range objects.KongPlugins { @@ -186,6 +216,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(p) } kongClusterPluginsStore := cache.NewStore(clusterResourceKeyFunc) for _, p := range objects.KongClusterPlugins { @@ -193,6 +224,7 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(p) } knativeIngressStore := cache.NewStore(keyFunc) @@ -201,12 +233,14 @@ func NewFakeStore( if err != nil { return nil, err } + clientBuilder.WithObjects(ingress) } - s = Store{ + + client := clientBuilder.Build() + + s := Store{ + client: client, stores: CacheStores{ - IngressV1beta1: ingressV1beta1Store, - IngressV1: ingressV1Store, - IngressClassV1: ingressClassV1Store, HTTPRoute: httprouteStore, UDPRoute: udprouteStore, TCPRoute: tcprouteStore, diff --git a/internal/store/fake_store_test.go b/internal/store/fake_store_test.go index b33d5fcddf..b3b0c84a88 100644 --- a/internal/store/fake_store_test.go +++ b/internal/store/fake_store_test.go @@ -1,6 +1,7 @@ package store import ( + "context" "errors" "testing" @@ -158,8 +159,8 @@ func TestFakeStoreIngressV1beta1(t *testing.T) { store, err := NewFakeStore(FakeObjects{IngressesV1beta1: ingresses}) require.Nil(err) require.NotNil(store) - assert.Len(store.ListIngressesV1beta1(), 1) - assert.Len(store.ListIngressesV1(), 0) + assert.Len(store.ListIngressesV1beta1(context.TODO()), 1) + assert.Len(store.ListIngressesV1(context.TODO()), 0) } func TestFakeStoreIngressV1(t *testing.T) { @@ -204,7 +205,7 @@ func TestFakeStoreIngressV1(t *testing.T) { }, { ObjectMeta: metav1.ObjectMeta{ - Name: "bar", + Name: "bar1", Namespace: "default", Annotations: map[string]string{ annotations.IngressClassKey: "not-kong", @@ -238,7 +239,7 @@ func TestFakeStoreIngressV1(t *testing.T) { }, { ObjectMeta: metav1.ObjectMeta{ - Name: "bar", + Name: "bar2", Namespace: "default", Annotations: map[string]string{ annotations.IngressClassKey: "skip-me-im-not-default", @@ -251,7 +252,7 @@ func TestFakeStoreIngressV1(t *testing.T) { }, { ObjectMeta: metav1.ObjectMeta{ - Name: "bar", + Name: "bar3", Namespace: "default", }, Spec: netv1.IngressSpec{ @@ -263,8 +264,8 @@ func TestFakeStoreIngressV1(t *testing.T) { store, err := NewFakeStore(FakeObjects{IngressesV1: ingresses}) require.Nil(err) require.NotNil(store) - assert.Len(store.ListIngressesV1(), 2) - assert.Len(store.ListIngressesV1beta1(), 0) + assert.Len(store.ListIngressesV1(context.TODO()), 2) + assert.Len(store.ListIngressesV1beta1(context.TODO()), 0) } func TestFakeStoreIngressClassV1(t *testing.T) { @@ -300,7 +301,7 @@ func TestFakeStoreIngressClassV1(t *testing.T) { store, err := NewFakeStore(FakeObjects{IngressClassesV1: classes}) require.Nil(err) require.NotNil(store) - assert.Len(store.ListIngressClassesV1(), 2) + assert.Len(store.ListIngressClassesV1(context.TODO()), 2) } func TestFakeStoreListTCPIngress(t *testing.T) { diff --git a/internal/store/store.go b/internal/store/store.go index 93b853fc4e..3e4ed94962 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -17,6 +17,7 @@ limitations under the License. package store import ( + "context" "fmt" "reflect" "sort" @@ -27,6 +28,7 @@ import ( corev1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" netv1beta1 "k8s.io/api/networking/v1beta1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme" "k8s.io/apimachinery/pkg/labels" @@ -37,6 +39,7 @@ import ( "k8s.io/apimachinery/pkg/selection" "k8s.io/client-go/tools/cache" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "sigs.k8s.io/yaml" @@ -78,13 +81,13 @@ type Storer interface { GetKongClusterPlugin(name string) (*kongv1.KongClusterPlugin, error) GetKongConsumer(namespace, name string) (*kongv1.KongConsumer, error) GetIngressClassName() string - GetIngressClassV1(name string) (*netv1.IngressClass, error) + GetIngressClassV1(ctx context.Context, name string) (*netv1.IngressClass, error) GetIngressClassParametersV1Alpha1(ingressClass *netv1.IngressClass) (*kongv1alpha1.IngressClassParameters, error) GetGateway(namespace string, name string) (*gatewayv1beta1.Gateway, error) - ListIngressesV1beta1() []*netv1beta1.Ingress - ListIngressesV1() []*netv1.Ingress - ListIngressClassesV1() []*netv1.IngressClass + ListIngressesV1beta1(ctx context.Context) []*netv1beta1.Ingress + ListIngressesV1(ctx context.Context) []*netv1.Ingress + ListIngressClassesV1(ctx context.Context) []*netv1.IngressClass ListIngressClassParametersV1Alpha1() []*kongv1alpha1.IngressClassParameters ListHTTPRoutes() ([]*gatewayv1beta1.HTTPRoute, error) ListUDPRoutes() ([]*gatewayv1alpha2.UDPRoute, error) @@ -109,6 +112,8 @@ type Storer interface { // be synced and updated by the caller. // It is ingressClass filter aware. type Store struct { + client client.Client + stores CacheStores ingressClass string @@ -126,12 +131,9 @@ var _ Storer = Store{} // the Ingress Controller reads. type CacheStores struct { // Core Kubernetes Stores - IngressV1beta1 cache.Store - IngressV1 cache.Store - IngressClassV1 cache.Store - Service cache.Store - Secret cache.Store - Endpoint cache.Store + Service cache.Store + Secret cache.Store + Endpoint cache.Store // Gateway API Stores HTTPRoute cache.Store @@ -155,18 +157,19 @@ type CacheStores struct { KnativeIngress cache.Store l *sync.RWMutex + + client client.Client } // NewCacheStores is a convenience function for CacheStores to initialize all attributes with new cache stores. -func NewCacheStores() CacheStores { +func NewCacheStores(client client.Client) CacheStores { return CacheStores{ + client: client, + // Core Kubernetes Stores - IngressV1beta1: cache.NewStore(keyFunc), - IngressV1: cache.NewStore(keyFunc), - IngressClassV1: cache.NewStore(clusterResourceKeyFunc), - Service: cache.NewStore(keyFunc), - Secret: cache.NewStore(keyFunc), - Endpoint: cache.NewStore(keyFunc), + Service: cache.NewStore(keyFunc), + Secret: cache.NewStore(keyFunc), + Endpoint: cache.NewStore(keyFunc), // Gateway API Stores HTTPRoute: cache.NewStore(keyFunc), UDPRoute: cache.NewStore(keyFunc), @@ -192,7 +195,7 @@ func NewCacheStores() CacheStores { // NewCacheStoresFromObjYAML provides a new CacheStores object given any number of byte arrays containing // YAML Kubernetes objects. An error is returned if any provided YAML was not a valid Kubernetes object. -func NewCacheStoresFromObjYAML(objs ...[]byte) (c CacheStores, err error) { +func NewCacheStoresFromObjYAML(client client.Client, objs ...[]byte) (c CacheStores, err error) { kobjs := make([]runtime.Object, 0, len(objs)) sr := serializer.NewYAMLSerializer( yamlserializer.DefaultMetaFactory, @@ -206,15 +209,15 @@ func NewCacheStoresFromObjYAML(objs ...[]byte) (c CacheStores, err error) { } kobjs = append(kobjs, kobj) } - return NewCacheStoresFromObjs(kobjs...) + return NewCacheStoresFromObjs(client, kobjs...) } // NewCacheStoresFromObjs provides a new CacheStores object given any number of Kubernetes // objects that should be pre-populated. This function will sort objects into the appropriate // sub-storage (e.g. IngressV1, TCPIngress, e.t.c.) but will produce an error if any of the // input objects are erroneous or otherwise unusable as Kubernetes objects. -func NewCacheStoresFromObjs(objs ...runtime.Object) (CacheStores, error) { - c := NewCacheStores() +func NewCacheStoresFromObjs(client client.Client, objs ...runtime.Object) (CacheStores, error) { + c := NewCacheStores(client) for _, obj := range objs { typedObj, err := mkObjFromGVK(obj.GetObjectKind().GroupVersionKind()) if err != nil { @@ -241,12 +244,6 @@ func (c CacheStores) Get(obj runtime.Object) (item interface{}, exists bool, err // ---------------------------------------------------------------------------- // Kubernetes Core API Support // ---------------------------------------------------------------------------- - case *netv1beta1.Ingress: - return c.IngressV1beta1.Get(obj) - case *netv1.Ingress: - return c.IngressV1.Get(obj) - case *netv1.IngressClass: - return c.IngressClassV1.Get(obj) case *corev1.Service: return c.Service.Get(obj) case *corev1.Secret: @@ -306,12 +303,6 @@ func (c CacheStores) Add(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kubernetes Core API Support // ---------------------------------------------------------------------------- - case *netv1beta1.Ingress: - return c.IngressV1beta1.Add(obj) - case *netv1.Ingress: - return c.IngressV1.Add(obj) - case *netv1.IngressClass: - return c.IngressClassV1.Add(obj) case *corev1.Service: return c.Service.Add(obj) case *corev1.Secret: @@ -372,12 +363,7 @@ func (c CacheStores) Delete(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kubernetes Core API Support // ---------------------------------------------------------------------------- - case *netv1beta1.Ingress: - return c.IngressV1beta1.Delete(obj) - case *netv1.Ingress: - return c.IngressV1.Delete(obj) - case *netv1.IngressClass: - return c.IngressClassV1.Delete(obj) + case *corev1.Service: return c.Service.Delete(obj) case *corev1.Secret: @@ -429,8 +415,9 @@ func (c CacheStores) Delete(obj runtime.Object) error { } // New creates a new object store to be used in the ingress controller. -func New(cs CacheStores, ingressClass string, logger logrus.FieldLogger) Storer { +func New(client client.Client, cs CacheStores, ingressClass string, logger logrus.FieldLogger) Storer { return Store{ + client: client, stores: cs, ingressClass: ingressClass, ingressClassMatching: annotations.ExactClassMatch, @@ -467,25 +454,25 @@ func (s Store) GetService(namespace, name string) (*corev1.Service, error) { } // ListIngressesV1 returns the list of Ingresses in the Ingress v1 store. -func (s Store) ListIngressesV1() []*netv1.Ingress { - // filter ingress rules +func (s Store) ListIngressesV1(ctx context.Context) []*netv1.Ingress { var ingresses []*netv1.Ingress - for _, item := range s.stores.IngressV1.List() { - ing, ok := item.(*netv1.Ingress) - if !ok { - s.logger.Warnf("listIngressesV1: dropping object of unexpected type: %#v", item) - continue - } + var ingressesV1 netv1.IngressList + if err := s.client.List(ctx, &ingressesV1); err != nil { + s.logger.Errorf("failed to list networking v1 Ingresses: %v", err) + } + + for i := range ingressesV1.Items { + ing := ingressesV1.Items[i] if ing.ObjectMeta.GetAnnotations()[annotations.IngressClassKey] != "" { if !s.isValidIngressClass(&ing.ObjectMeta, annotations.IngressClassKey, s.ingressClassMatching) { continue } } else if ing.Spec.IngressClassName != nil { - if !s.isValidIngressV1Class(ing, s.ingressClassMatching) { + if !s.isValidIngressV1Class(&ing, s.ingressClassMatching) { continue } } else { - class, err := s.GetIngressClassV1(s.ingressClass) + class, err := s.GetIngressClassV1(ctx, s.ingressClass) if err != nil { s.logger.Debugf("IngressClass %s not found", s.ingressClass) continue @@ -494,7 +481,7 @@ func (s Store) ListIngressesV1() []*netv1.Ingress { continue } } - ingresses = append(ingresses, ing) + ingresses = append(ingresses, &ing) } sort.SliceStable(ingresses, func(i, j int) bool { @@ -505,20 +492,19 @@ func (s Store) ListIngressesV1() []*netv1.Ingress { return ingresses } -// ListIngressClassesV1 returns the list of Ingresses in the Ingress v1 store. -func (s Store) ListIngressClassesV1() []*netv1.IngressClass { +// ListIngressClassesV1 returns the list of IngressClasses. +func (s Store) ListIngressClassesV1(ctx context.Context) []*netv1.IngressClass { // filter ingress rules var classes []*netv1.IngressClass - for _, item := range s.stores.IngressClassV1.List() { - class, ok := item.(*netv1.IngressClass) - if !ok { - s.logger.Warnf("listIngressClassesV1: dropping object of unexpected type: %#v", item) - continue - } - if class.Spec.Controller != IngressClassKongController { + var classList netv1.IngressClassList + if err := s.client.List(ctx, &classList); err != nil { + s.logger.Errorf("failed to list networking v1 IngressClasses: %v", err) + } + for i := range classList.Items { + if classList.Items[i].Spec.Controller != IngressClassKongController { continue } - classes = append(classes, class) + classes = append(classes, &classList.Items[i]) } sort.SliceStable(classes, func(i, j int) bool { @@ -551,15 +537,19 @@ func (s Store) ListIngressClassParametersV1Alpha1() []*kongv1alpha1.IngressClass } // ListIngressesV1beta1 returns the list of Ingresses in the Ingress v1beta1 store. -func (s Store) ListIngressesV1beta1() []*netv1beta1.Ingress { +func (s Store) ListIngressesV1beta1(ctx context.Context) []*netv1beta1.Ingress { // filter ingress rules var ingresses []*netv1beta1.Ingress - for _, item := range s.stores.IngressV1beta1.List() { - ing := s.networkingIngressV1Beta1(item) + var ingressesV1Beta1 netv1beta1.IngressList + if err := s.client.List(ctx, &ingressesV1Beta1); err != nil { + s.logger.Errorf("failed to list networking v1 Ingresses: %v", err) + } + for _, item := range ingressesV1Beta1.Items { + ing := item if !s.isValidIngressClass(&ing.ObjectMeta, annotations.IngressClassKey, s.ingressClassMatching) { continue } - ingresses = append(ingresses, ing) + ingresses = append(ingresses, &ing) } sort.SliceStable(ingresses, func(i, j int) bool { return strings.Compare(fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), @@ -825,15 +815,22 @@ func (s Store) GetIngressClassName() string { } // GetIngressClassV1 returns the 'name' IngressClass resource. -func (s Store) GetIngressClassV1(name string) (*netv1.IngressClass, error) { - p, exists, err := s.stores.IngressClassV1.GetByKey(name) +func (s Store) GetIngressClassV1(ctx context.Context, name string) (*netv1.IngressClass, error) { + var ( + ingressClass netv1.IngressClass + key = client.ObjectKey{ + Name: name, + } + ) + + err := s.client.Get(ctx, key, &ingressClass) if err != nil { return nil, err } - if !exists { + if apierrors.IsNotFound(err) { return nil, ErrNotFound{fmt.Sprintf("IngressClass %v not found", name)} } - return p.(*netv1.IngressClass), nil + return &ingressClass, nil } // GetIngressClassParametersV1Alpha1 returns IngressClassParameters for provided @@ -1016,7 +1013,7 @@ func (s Store) networkingIngressV1Beta1(obj interface{}) *netv1beta1.Ingress { // getIngressClassHandling returns annotations.ExactOrEmptyClassMatch if an IngressClass is the default class, or // annotations.ExactClassMatch if the IngressClass is not default or does not exist. func (s Store) getIngressClassHandling() annotations.ClassMatching { - class, err := s.GetIngressClassV1(s.ingressClass) + class, err := s.GetIngressClassV1(context.TODO(), s.ingressClass) //nolint:contextcheck if err != nil { s.logger.Debugf("IngressClass %s not found", s.ingressClass) return annotations.ExactClassMatch @@ -1052,6 +1049,8 @@ func mkObjFromGVK(gvk schema.GroupVersionKind) (runtime.Object, error) { // ---------------------------------------------------------------------------- // Kubernetes Core APIs // ---------------------------------------------------------------------------- + case netv1.SchemeGroupVersion.WithKind("IngressClass"): + return &netv1.IngressClass{}, nil case netv1.SchemeGroupVersion.WithKind("Ingress"): return &netv1.Ingress{}, nil case kongv1beta1.SchemeGroupVersion.WithKind("TCPIngress"): diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 5f2f179c8b..51016db5a1 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -14,6 +14,7 @@ import ( netv1beta1 "k8s.io/api/networking/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" ) @@ -107,7 +108,8 @@ spec: `) t.Log("creating a new cache store from object yaml files") - cs, err := NewCacheStoresFromObjYAML(svcYAML, ingYAML) + client := ctrlfake.NewClientBuilder().Build() + cs, err := NewCacheStoresFromObjYAML(client, svcYAML, ingYAML) // TODO(pmalek) require.NoError(t, err) t.Log("verifying that the cache store doesnt try to retrieve unsupported object types") @@ -117,9 +119,9 @@ spec: assert.False(t, exists) t.Log("verifying the integrity of the cache store") - assert.Len(t, cs.IngressV1.List(), 1) + // assert.Len(t, cs.IngressV1.List(), 1) assert.Len(t, cs.Service.List(), 1) - assert.Len(t, cs.IngressV1beta1.List(), 0) + // assert.Len(t, cs.IngressV1beta1.List(), 0) assert.Len(t, cs.KongIngress.List(), 0) _, exists, err = cs.Get(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: "doesntexist", Name: "doesntexist"}}) assert.NoError(t, err) From 166801e1e9e1eb7fcf44c28f28e553680ef97ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Thu, 6 Apr 2023 13:06:32 +0200 Subject: [PATCH 2/4] wip2 --- internal/admission/validator.go | 8 +- internal/dataplane/kongstate/kongstate.go | 25 +- .../dataplane/kongstate/kongstate_test.go | 3 +- internal/dataplane/kongstate/util.go | 25 +- internal/dataplane/kongstate/util_test.go | 5 +- internal/dataplane/parser/ingressrules.go | 10 +- .../dataplane/parser/ingressrules_test.go | 5 +- internal/dataplane/parser/parser.go | 34 +- internal/dataplane/parser/parser_test.go | 32 +- .../dataplane/parser/translate_secrets.go | 13 +- .../parser/translate_secrets_test.go | 3 +- internal/store/fake_store.go | 6 - internal/store/fake_store_test.go | 34 +- internal/store/store.go | 320 ++++++++++-------- internal/store/store_test.go | 3 +- 15 files changed, 279 insertions(+), 247 deletions(-) diff --git a/internal/admission/validator.go b/internal/admission/validator.go index f3e25edf94..4dd9e39a98 100644 --- a/internal/admission/validator.go +++ b/internal/admission/validator.go @@ -111,7 +111,7 @@ func (validator KongHTTPValidator) ValidateConsumer( ignoredSecrets := make(map[string]map[string]struct{}) for _, secretName := range consumer.Credentials { // retrieve the credentials secret - secret, err := validator.SecretGetter.GetSecret(consumer.Namespace, secretName) + secret, err := validator.SecretGetter.GetSecret(ctx, consumer.Namespace, secretName) if err != nil { if apierrors.IsNotFound(err) { return false, ErrTextConsumerCredentialSecretNotFound, err @@ -236,7 +236,7 @@ func (validator KongHTTPValidator) ValidatePlugin( if len(plugin.Config) > 0 { return false, ErrTextPluginUsesBothConfigTypes, nil } - config, err := kongstate.SecretToConfiguration(validator.SecretGetter, (*k8sPlugin.ConfigFrom).SecretValue, k8sPlugin.Namespace) + config, err := kongstate.SecretToConfiguration(ctx, validator.SecretGetter, (*k8sPlugin.ConfigFrom).SecretValue, k8sPlugin.Namespace) if err != nil { return false, ErrTextPluginSecretConfigUnretrievable, err } @@ -433,9 +433,9 @@ type managerClientSecretGetter struct { managerClient client.Client } -func (m *managerClientSecretGetter) GetSecret(namespace, name string) (*corev1.Secret, error) { +func (m *managerClientSecretGetter) GetSecret(ctx context.Context, namespace, name string) (*corev1.Secret, error) { secret := &corev1.Secret{} - return secret, m.managerClient.Get(context.Background(), client.ObjectKey{ + return secret, m.managerClient.Get(ctx, client.ObjectKey{ Namespace: namespace, Name: name, }, secret) diff --git a/internal/dataplane/kongstate/kongstate.go b/internal/dataplane/kongstate/kongstate.go index 2a5c1c5fd8..86f3f44506 100644 --- a/internal/dataplane/kongstate/kongstate.go +++ b/internal/dataplane/kongstate/kongstate.go @@ -1,6 +1,7 @@ package kongstate import ( + "context" "fmt" "strconv" "strings" @@ -48,11 +49,11 @@ func (ks *KongState) SanitizedCopy() *KongState { } } -func (ks *KongState) FillConsumersAndCredentials(log logrus.FieldLogger, s store.Storer) { +func (ks *KongState) FillConsumersAndCredentials(ctx context.Context, log logrus.FieldLogger, s store.Storer) { consumerIndex := make(map[string]Consumer) // build consumer index - for _, consumer := range s.ListKongConsumers() { + for _, consumer := range s.ListKongConsumers(ctx) { var c Consumer if consumer.Username == "" && consumer.CustomID == "" { continue @@ -75,7 +76,7 @@ func (ks *KongState) FillConsumersAndCredentials(log logrus.FieldLogger, s store "secret_name": cred, "secret_namespace": consumer.Namespace, }) - secret, err := s.GetSecret(consumer.Namespace, cred) + secret, err := s.GetSecret(ctx, consumer.Namespace, cred) //nolint:contextcheck if err != nil { log.WithError(err).Error("failed to fetch secret") continue @@ -250,13 +251,13 @@ func (ks *KongState) getPluginRelations() map[string]util.ForeignRelations { return pluginRels } -func buildPlugins(log logrus.FieldLogger, s store.Storer, pluginRels map[string]util.ForeignRelations) []Plugin { +func buildPlugins(ctx context.Context, log logrus.FieldLogger, s store.Storer, pluginRels map[string]util.ForeignRelations) []Plugin { var plugins []Plugin for pluginIdentifier, relations := range pluginRels { identifier := strings.Split(pluginIdentifier, ":") namespace, kongPluginName := identifier[0], identifier[1] - plugin, err := getPlugin(s, namespace, kongPluginName) + plugin, err := getPlugin(ctx, s, namespace, kongPluginName) if err != nil { log.WithFields(logrus.Fields{ "kongplugin_name": kongPluginName, @@ -282,7 +283,7 @@ func buildPlugins(log logrus.FieldLogger, s store.Storer, pluginRels map[string] } } - globalPlugins, err := globalPlugins(log, s) + globalPlugins, err := globalPlugins(ctx, log, s) if err != nil { log.WithError(err).Error("failed to fetch global plugins") } @@ -291,10 +292,10 @@ func buildPlugins(log logrus.FieldLogger, s store.Storer, pluginRels map[string] return plugins } -func globalPlugins(log logrus.FieldLogger, s store.Storer) ([]Plugin, error) { +func globalPlugins(ctx context.Context, log logrus.FieldLogger, s store.Storer) ([]Plugin, error) { // removed as of 0.10.0 // only retrieved now to warn users - globalPlugins, err := s.ListGlobalKongPlugins() + globalPlugins, err := s.ListGlobalKongPlugins(ctx) if err != nil { return nil, fmt.Errorf("error listing global KongPlugins: %w", err) } @@ -311,7 +312,7 @@ func globalPlugins(log logrus.FieldLogger, s store.Storer) ([]Plugin, error) { // This is important since if a user comes in to k8s and creates a new // CRD, the user now deleted an older plugin - globalClusterPlugins, err := s.ListGlobalKongClusterPlugins() + globalClusterPlugins, err := s.ListGlobalKongClusterPlugins(ctx) if err != nil { return nil, fmt.Errorf("error listing global KongClusterPlugins: %w", err) } @@ -332,7 +333,7 @@ func globalPlugins(log logrus.FieldLogger, s store.Storer) ([]Plugin, error) { duplicates = append(duplicates, pluginName) continue } - if plugin, err := kongPluginFromK8SClusterPlugin(s, k8sPlugin); err == nil { + if plugin, err := kongPluginFromK8SClusterPlugin(ctx, s, k8sPlugin); err == nil { res[pluginName] = Plugin{ Plugin: plugin, } @@ -352,6 +353,6 @@ func globalPlugins(log logrus.FieldLogger, s store.Storer) ([]Plugin, error) { return plugins, nil } -func (ks *KongState) FillPlugins(log logrus.FieldLogger, s store.Storer) { - ks.Plugins = buildPlugins(log, s, ks.getPluginRelations()) +func (ks *KongState) FillPlugins(ctx context.Context, log logrus.FieldLogger, s store.Storer) { + ks.Plugins = buildPlugins(ctx, log, s, ks.getPluginRelations()) } diff --git a/internal/dataplane/kongstate/kongstate_test.go b/internal/dataplane/kongstate/kongstate_test.go index f501958be5..5a93db8d80 100644 --- a/internal/dataplane/kongstate/kongstate_test.go +++ b/internal/dataplane/kongstate/kongstate_test.go @@ -1,6 +1,7 @@ package kongstate import ( + "context" "reflect" "testing" @@ -386,7 +387,7 @@ func TestFillConsumersAndCredentials(t *testing.T) { state := KongState{ Version: semver.MustParse("2.3.2"), } - state.FillConsumersAndCredentials(logrus.New(), store) + state.FillConsumersAndCredentials(context.TODO(), logrus.New(), store) //nolint:contextcheck assert.Equal(t, want.Consumers[0].Consumer.Username, state.Consumers[0].Consumer.Username) assert.Equal(t, want.Consumers[0].Consumer.CustomID, state.Consumers[0].Consumer.CustomID) assert.Equal(t, want.Consumers[0].KeyAuths[0].Key, state.Consumers[0].KeyAuths[0].Key) diff --git a/internal/dataplane/kongstate/util.go b/internal/dataplane/kongstate/util.go index 1db801a4a7..b70d510627 100644 --- a/internal/dataplane/kongstate/util.go +++ b/internal/dataplane/kongstate/util.go @@ -1,6 +1,7 @@ package kongstate import ( + "context" "encoding/json" "errors" "fmt" @@ -79,14 +80,14 @@ func getKongIngressFromObjAnnotations( } // getPlugin constructs a plugins from a KongPlugin resource. -func getPlugin(s store.Storer, namespace, name string) (kong.Plugin, error) { +func getPlugin(ctx context.Context, s store.Storer, namespace, name string) (kong.Plugin, error) { var plugin kong.Plugin - k8sPlugin, err := s.GetKongPlugin(namespace, name) + k8sPlugin, err := s.GetKongPlugin(ctx, namespace, name) if err != nil { // if no namespaced plugin definition, then // search for cluster level-plugin definition if errors.As(err, &store.ErrNotFound{}) { - clusterPlugin, err := s.GetKongClusterPlugin(name) + clusterPlugin, err := s.GetKongClusterPlugin(ctx, name) // not found if errors.As(err, &store.ErrNotFound{}) { return plugin, errors.New( @@ -98,7 +99,7 @@ func getPlugin(s store.Storer, namespace, name string) (kong.Plugin, error) { if clusterPlugin.PluginName == "" { return plugin, fmt.Errorf("invalid empty 'plugin' property") } - plugin, err = kongPluginFromK8SClusterPlugin(s, *clusterPlugin) + plugin, err = kongPluginFromK8SClusterPlugin(ctx, s, *clusterPlugin) return plugin, err } } @@ -107,11 +108,12 @@ func getPlugin(s store.Storer, namespace, name string) (kong.Plugin, error) { return plugin, fmt.Errorf("invalid empty 'plugin' property") } - plugin, err = kongPluginFromK8SPlugin(s, *k8sPlugin) + plugin, err = kongPluginFromK8SPlugin(ctx, s, *k8sPlugin) return plugin, err } func kongPluginFromK8SClusterPlugin( + ctx context.Context, s store.Storer, k8sPlugin configurationv1.KongClusterPlugin, ) (kong.Plugin, error) { @@ -129,6 +131,7 @@ func kongPluginFromK8SClusterPlugin( if k8sPlugin.ConfigFrom != nil { var err error config, err = namespacedSecretToConfiguration( + ctx, s, (*k8sPlugin.ConfigFrom).SecretValue) if err != nil { @@ -165,6 +168,7 @@ func protocolsToStrings(protocols []configurationv1.KongProtocol) (res []string) } func kongPluginFromK8SPlugin( + ctx context.Context, s store.Storer, k8sPlugin configurationv1.KongPlugin, ) (kong.Plugin, error) { @@ -182,8 +186,7 @@ func kongPluginFromK8SPlugin( } if k8sPlugin.ConfigFrom != nil { var err error - config, err = SecretToConfiguration(s, - (*k8sPlugin.ConfigFrom).SecretValue, k8sPlugin.Namespace) + config, err = SecretToConfiguration(ctx, s, (*k8sPlugin.ConfigFrom).SecretValue, k8sPlugin.Namespace) if err != nil { return kong.Plugin{}, fmt.Errorf("error parsing config for KongPlugin '%v/%v': %w", @@ -216,6 +219,7 @@ func RawConfigToConfiguration(config apiextensionsv1.JSON) (kong.Configuration, } func namespacedSecretToConfiguration( + ctx context.Context, s store.Storer, reference configurationv1.NamespacedSecretValueFromSource) ( kong.Configuration, error, @@ -224,19 +228,20 @@ func namespacedSecretToConfiguration( Secret: reference.Secret, Key: reference.Key, } - return SecretToConfiguration(s, bareReference, reference.Namespace) + return SecretToConfiguration(ctx, s, bareReference, reference.Namespace) } type SecretGetter interface { - GetSecret(namespace, name string) (*corev1.Secret, error) + GetSecret(ctx context.Context, namespace, name string) (*corev1.Secret, error) } func SecretToConfiguration( + ctx context.Context, s SecretGetter, reference configurationv1.SecretValueFromSource, namespace string) ( kong.Configuration, error, ) { - secret, err := s.GetSecret(namespace, reference.Secret) + secret, err := s.GetSecret(ctx, namespace, reference.Secret) if err != nil { return kong.Configuration{}, fmt.Errorf( "error fetching plugin configuration secret '%v/%v': %w", diff --git a/internal/dataplane/kongstate/util_test.go b/internal/dataplane/kongstate/util_test.go index 7723e64428..953a4d7d26 100644 --- a/internal/dataplane/kongstate/util_test.go +++ b/internal/dataplane/kongstate/util_test.go @@ -1,6 +1,7 @@ package kongstate import ( + "context" "regexp" "testing" @@ -145,7 +146,7 @@ func TestKongPluginFromK8SClusterPlugin(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := kongPluginFromK8SClusterPlugin(store, tt.args.plugin) + got, err := kongPluginFromK8SClusterPlugin(context.TODO(), store, tt.args.plugin) //nolint:contextcheck if (err != nil) != tt.wantErr { t.Errorf("kongPluginFromK8SClusterPlugin error = %v, wantErr %v", err, tt.wantErr) return @@ -284,7 +285,7 @@ func TestKongPluginFromK8SPlugin(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := kongPluginFromK8SPlugin(store, tt.args.plugin) + got, err := kongPluginFromK8SPlugin(context.TODO(), store, tt.args.plugin) //nolint:contextcheck if (err != nil) != tt.wantErr { t.Errorf("kongPluginFromK8SPlugin error = %v, wantErr %v", err, tt.wantErr) return diff --git a/internal/dataplane/parser/ingressrules.go b/internal/dataplane/parser/ingressrules.go index 216e202746..38b1797199 100644 --- a/internal/dataplane/parser/ingressrules.go +++ b/internal/dataplane/parser/ingressrules.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" "strings" @@ -50,7 +51,7 @@ func mergeIngressRules(objs ...ingressRules) ingressRules { // populateServices populates the ServiceNameToServices map with additional information // and returns a map of services to be skipped. -func (ir *ingressRules) populateServices(log logrus.FieldLogger, s store.Storer, failuresCollector *failures.ResourceFailuresCollector) map[string]interface{} { +func (ir *ingressRules) populateServices(ctx context.Context, log logrus.FieldLogger, s store.Storer, failuresCollector *failures.ResourceFailuresCollector) map[string]interface{} { serviceNamesToSkip := make(map[string]interface{}) // populate Kubernetes Service @@ -61,7 +62,7 @@ func (ir *ingressRules) populateServices(log logrus.FieldLogger, s store.Storer, // collect all the Kubernetes services configured for the service backends, // and all the annotations in use across all services (when applicable). - k8sServices, seenAnnotations := getK8sServicesForBackends(log, s, service.Namespace, service.Backends) + k8sServices, seenAnnotations := getK8sServicesForBackends(ctx, log, s, service.Namespace, service.Backends) // if the Kubernetes services have been deemed invalid, log an error message // and skip the current service. @@ -81,7 +82,7 @@ func (ir *ingressRules) populateServices(log logrus.FieldLogger, s store.Storer, secretName := annotations.ExtractClientCertificate(k8sService.Annotations) if secretName != "" { secretKey := k8sService.Namespace + "/" + secretName - secret, err := s.GetSecret(k8sService.Namespace, secretName) + secret, err := s.GetSecret(ctx, k8sService.Namespace, secretName) if err != nil { failuresCollector.PushResourceFailure( fmt.Sprintf("failed to fetch secret '%s': %v", secretKey, err), k8sService, @@ -243,6 +244,7 @@ func (s SNIs) Hosts() []string { } func getK8sServicesForBackends( + ctx context.Context, log logrus.FieldLogger, storer store.Storer, namespace string, @@ -260,7 +262,7 @@ func getK8sServicesForBackends( if backend.Namespace != "" { backendNamespace = backend.Namespace } - k8sService, err := storer.GetService(backendNamespace, backend.Name) + k8sService, err := storer.GetService(ctx, backendNamespace, backend.Name) if err != nil { log.WithFields(logrus.Fields{ "service_name": backend.PortDef.Name, diff --git a/internal/dataplane/parser/ingressrules_test.go b/internal/dataplane/parser/ingressrules_test.go index afd7d49414..e7c867c33d 100644 --- a/internal/dataplane/parser/ingressrules_test.go +++ b/internal/dataplane/parser/ingressrules_test.go @@ -2,6 +2,7 @@ package parser import ( "bytes" + "context" "testing" "github.com/kong/go-kong/kong" @@ -351,7 +352,7 @@ func TestGetK8sServicesForBackends(t *testing.T) { logger := logrus.New() logger.SetOutput(stdout) - services, annotations := getK8sServicesForBackends(logger, storer, tt.namespace, tt.backends) + services, annotations := getK8sServicesForBackends(context.TODO(), logger, storer, tt.namespace, tt.backends) //nolint:contextcheck assert.Equal(t, tt.expectedServices, services) assert.Equal(t, tt.expectedAnnotations, annotations) for _, expectedLogEntry := range tt.expectedLogEntries { @@ -654,7 +655,7 @@ func TestPopulateServices(t *testing.T) { logger, _ := test.NewNullLogger() failuresCollector, err := failures.NewResourceFailuresCollector(logger) require.NoError(t, err) - servicesToBeSkipped := ingressRules.populateServices(logrus.New(), fakeStore, failuresCollector) + servicesToBeSkipped := ingressRules.populateServices(context.TODO(), logrus.New(), fakeStore, failuresCollector) //nolint:contextcheck require.Equal(t, tc.serviceNamesToSkip, servicesToBeSkipped) require.Len(t, failuresCollector.PopResourceFailures(), len(servicesToBeSkipped), "expecting as many translation failures as services to skip") }) diff --git a/internal/dataplane/parser/parser.go b/internal/dataplane/parser/parser.go index 537eadd0c6..1a04f40e57 100644 --- a/internal/dataplane/parser/parser.go +++ b/internal/dataplane/parser/parser.go @@ -97,7 +97,7 @@ func (p *Parser) Build(ctx context.Context) (*kongstate.KongState, []failures.Re // populate any Kubernetes Service objects relevant objects and get the // services to be skipped because of annotations inconsistency - servicesToBeSkipped := ingressRules.populateServices(p.logger, p.storer, p.failuresCollector) + servicesToBeSkipped := ingressRules.populateServices(ctx, p.logger, p.storer, p.failuresCollector) // add the routes and services to the state var result kongstate.KongState @@ -110,25 +110,25 @@ func (p *Parser) Build(ctx context.Context) (*kongstate.KongState, []failures.Re } // generate Upstreams and Targets from service defs - result.Upstreams = p.getUpstreams(ingressRules.ServiceNameToServices) + result.Upstreams = p.getUpstreams(ctx, ingressRules.ServiceNameToServices) // merge KongIngress with Routes, Services and Upstream result.FillOverrides(p.logger, p.storer) // generate consumers and credentials - result.FillConsumersAndCredentials(p.logger, p.storer) + result.FillConsumersAndCredentials(ctx, p.logger, p.storer) // process annotation plugins - result.FillPlugins(p.logger, p.storer) + result.FillPlugins(ctx, p.logger, p.storer) // generate Certificates and SNIs - ingressCerts := p.getCerts(ingressRules.SecretNameToSNIs) - gatewayCerts := p.getGatewayCerts() + ingressCerts := p.getCerts(ctx, ingressRules.SecretNameToSNIs) + gatewayCerts := p.getGatewayCerts(ctx) // note that ingress-derived certificates will take precedence over gateway-derived certificates for SNI assignment result.Certificates = mergeCerts(p.logger, ingressCerts, gatewayCerts) // populate CA certificates in Kong - result.CACertificates = p.getCACerts() + result.CACertificates = p.getCACerts(ctx) return &result, p.popTranslationFailures() } @@ -268,7 +268,7 @@ func findPort(svc *corev1.Service, wantPort kongstate.PortDef) (*corev1.ServiceP return nil, fmt.Errorf("no suitable port found") } -func (p *Parser) getUpstreams(serviceMap map[string]kongstate.Service) []kongstate.Upstream { +func (p *Parser) getUpstreams(ctx context.Context, serviceMap map[string]kongstate.Service) []kongstate.Upstream { upstreamDedup := make(map[string]struct{}, len(serviceMap)) var empty struct{} upstreams := make([]kongstate.Upstream, 0, len(serviceMap)) @@ -303,7 +303,7 @@ func (p *Parser) getUpstreams(serviceMap map[string]kongstate.Service) []kongsta } // get the new targets for this backend service - newTargets := getServiceEndpoints(p.logger, p.storer, k8sService, port) + newTargets := getServiceEndpoints(ctx, p.logger, p.storer, k8sService, port) //nolint:contextcheck if len(newTargets) == 0 { p.logger.WithField("service_name", *service.Name).Infof("no targets could be found for kubernetes service %s/%s", k8sService.Namespace, k8sService.Name) @@ -389,7 +389,7 @@ type certWrapper struct { CreationTimestamp metav1.Time } -func (p *Parser) getGatewayCerts() []certWrapper { +func (p *Parser) getGatewayCerts(ctx context.Context) []certWrapper { log := p.logger s := p.storer certs := []certWrapper{} @@ -444,7 +444,7 @@ func (p *Parser) getGatewayCerts() []certWrapper { } // retrieve the Secret and extract the PEM strings - secret, err := s.GetSecret(namespace, string(ref.Name)) + secret, err := s.GetSecret(ctx, namespace, string(ref.Name)) if err != nil { log.WithFields(logrus.Fields{ "gateway": gateway.Name, @@ -485,12 +485,12 @@ func (p *Parser) getGatewayCerts() []certWrapper { return certs } -func (p *Parser) getCerts(secretsToSNIs SecretNameToSNIs) []certWrapper { +func (p *Parser) getCerts(ctx context.Context, secretsToSNIs SecretNameToSNIs) []certWrapper { certs := []certWrapper{} for secretKey, SNIs := range secretsToSNIs.secretToSNIs { namespaceName := strings.Split(secretKey, "/") - secret, err := p.storer.GetSecret(namespaceName[0], namespaceName[1]) + secret, err := p.storer.GetSecret(ctx, namespaceName[0], namespaceName[1]) if err != nil { p.registerTranslationFailure(fmt.Sprintf("failed to fetch the secret (%s)", secretKey), SNIs.Parents()...) continue @@ -573,6 +573,7 @@ func mergeCerts(log logrus.FieldLogger, certLists ...[]certWrapper) []kongstate. } func getServiceEndpoints( + ctx context.Context, log logrus.FieldLogger, s store.Storer, svc *corev1.Service, @@ -601,7 +602,7 @@ func getServiceEndpoints( // check all protocols for associated endpoints endpoints := []util.Endpoint{} for protocol := range protocols { - newEndpoints := getEndpoints(log, svc, servicePort, protocol, s.GetEndpointsForService, isSvcUpstream) + newEndpoints := getEndpoints(ctx, log, svc, servicePort, protocol, s.GetEndpointsForService, isSvcUpstream) //nolint:contextcheck if len(newEndpoints) > 0 { endpoints = append(endpoints, newEndpoints...) } @@ -635,11 +636,12 @@ func getIngressClassParametersOrDefault(ctx context.Context, s store.Storer) (co // It also checks if the service is an upstream service either by its annotations // of by IngressClassParameters configuration provided as a flag. func getEndpoints( + ctx context.Context, log logrus.FieldLogger, s *corev1.Service, port *corev1.ServicePort, proto corev1.Protocol, - getEndpoints func(string, string) (*corev1.Endpoints, error), + getEndpoints func(context.Context, string, string) (*corev1.Endpoints, error), isSvcUpstream bool, ) []util.Endpoint { if s == nil || port == nil { @@ -680,7 +682,7 @@ func getEndpoints( } log.Debugf("fetching endpoints") - ep, err := getEndpoints(s.Namespace, s.Name) + ep, err := getEndpoints(ctx, s.Namespace, s.Name) if err != nil { log.WithError(err).Error("failed to fetch endpoints") return []util.Endpoint{} diff --git a/internal/dataplane/parser/parser_test.go b/internal/dataplane/parser/parser_test.go index 1481ae7cab..da2419378b 100644 --- a/internal/dataplane/parser/parser_test.go +++ b/internal/dataplane/parser/parser_test.go @@ -730,12 +730,12 @@ func TestSecretConfigurationPlugin(t *testing.T) { require.Empty(t, translationFailures) assert.NotNil(state) for _, testcase := range references { - config, err := kongstate.SecretToConfiguration(store, *testcase, "default") + config, err := kongstate.SecretToConfiguration(context.TODO(), store, *testcase, "default") //nolint:contextcheck assert.NotEmpty(config) assert.Nil(err) } for _, testcase := range badReferences { - config, err := kongstate.SecretToConfiguration(store, *testcase, "default") + config, err := kongstate.SecretToConfiguration(context.TODO(), store, *testcase, "default") //nolint:contextcheck assert.Empty(config) assert.NotEmpty(err) } @@ -3938,7 +3938,7 @@ func TestGetEndpoints(t *testing.T) { svc *corev1.Service port *corev1.ServicePort proto corev1.Protocol - fn func(string, string) (*corev1.Endpoints, error) + fn func(context.Context, string, string) (*corev1.Endpoints, error) result []util.Endpoint isServiceUpstream bool }{ @@ -3947,7 +3947,7 @@ func TestGetEndpoints(t *testing.T) { svc: nil, port: nil, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { return nil, nil }, + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { return nil, nil }, result: []util.Endpoint{}, }, { @@ -3955,7 +3955,7 @@ func TestGetEndpoints(t *testing.T) { svc: &corev1.Service{}, port: nil, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { return nil, nil }, + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { return nil, nil }, result: []util.Endpoint{}, }, { @@ -3963,7 +3963,7 @@ func TestGetEndpoints(t *testing.T) { svc: &corev1.Service{}, port: &corev1.ServicePort{Name: "default"}, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { return &corev1.Endpoints{}, nil }, + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { return &corev1.Endpoints{}, nil }, result: []util.Endpoint{}, }, { @@ -3985,7 +3985,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(80), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { return &corev1.Endpoints{}, nil }, result: []util.Endpoint{ @@ -4020,7 +4020,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(2080), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { return &corev1.Endpoints{}, nil }, result: []util.Endpoint{ @@ -4052,7 +4052,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(2080), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { return &corev1.Endpoints{}, nil }, result: []util.Endpoint{ @@ -4082,7 +4082,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(80), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { return nil, fmt.Errorf("unexpected error") }, result: []util.Endpoint{}, @@ -4106,7 +4106,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(80), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { nodeName := "dummy" return &corev1.Endpoints{ Subsets: []corev1.EndpointSubset{ @@ -4147,7 +4147,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(80), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { nodeName := "dummy" return &corev1.Endpoints{ Subsets: []corev1.EndpointSubset{ @@ -4188,7 +4188,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(80), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { nodeName := "dummy" return &corev1.Endpoints{ Subsets: []corev1.EndpointSubset{ @@ -4231,7 +4231,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromInt(80), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { nodeName := "dummy" return &corev1.Endpoints{ Subsets: []corev1.EndpointSubset{ @@ -4279,7 +4279,7 @@ func TestGetEndpoints(t *testing.T) { TargetPort: intstr.FromString("port-1"), }, proto: corev1.ProtocolTCP, - fn: func(string, string) (*corev1.Endpoints, error) { + fn: func(context.Context, string, string) (*corev1.Endpoints, error) { nodeName := "dummy" return &corev1.Endpoints{ Subsets: []corev1.EndpointSubset{ @@ -4317,7 +4317,7 @@ func TestGetEndpoints(t *testing.T) { for _, testCase := range tests { t.Run(testCase.name, func(t *testing.T) { - result := getEndpoints(logrus.New(), testCase.svc, testCase.port, testCase.proto, testCase.fn, testCase.isServiceUpstream) + result := getEndpoints(context.TODO(), logrus.New(), testCase.svc, testCase.port, testCase.proto, testCase.fn, testCase.isServiceUpstream) //nolint:contextcheck if len(testCase.result) != len(result) { t.Errorf("expected %v Endpoints but got %v", testCase.result, len(result)) } diff --git a/internal/dataplane/parser/translate_secrets.go b/internal/dataplane/parser/translate_secrets.go index 23841fb9f1..688cb454b4 100644 --- a/internal/dataplane/parser/translate_secrets.go +++ b/internal/dataplane/parser/translate_secrets.go @@ -1,6 +1,7 @@ package parser import ( + "context" "crypto/x509" "encoding/json" "encoding/pem" @@ -19,8 +20,8 @@ import ( // getCACerts translates CA certificates Secrets to kong.CACertificates. It ensures every certificate's structure and // validity. It skips Secrets that do not contain a valid certificate and reports translation failures for them. -func (p *Parser) getCACerts() []kong.CACertificate { - caCertSecrets, err := p.storer.ListCACerts() +func (p *Parser) getCACerts(ctx context.Context) []kong.CACertificate { + caCertSecrets, err := p.storer.ListCACerts(ctx) if err != nil { p.logger.WithError(err).Error("failed to list CA certs") return nil @@ -37,7 +38,7 @@ func (p *Parser) getCACerts() []kong.CACertificate { caCert, err := toKongCACertificate(certSecret, secretID) if err != nil { - relatedObjects := getPluginsAssociatedWithCACertSecret(secretID, p.storer) + relatedObjects := getPluginsAssociatedWithCACertSecret(ctx, secretID, p.storer) relatedObjects = append(relatedObjects, certSecret.DeepCopy()) p.registerTranslationFailure(fmt.Sprintf("invalid CA certificate: %s", err), relatedObjects...) continue @@ -76,7 +77,7 @@ func toKongCACertificate(certSecret *corev1.Secret, secretID string) (kong.CACer }, nil } -func getPluginsAssociatedWithCACertSecret(secretID string, storer store.Storer) []client.Object { +func getPluginsAssociatedWithCACertSecret(ctx context.Context, secretID string, storer store.Storer) []client.Object { refersToSecret := func(pluginConfig v1.JSON) bool { cfg := struct { CACertificates []string `json:"ca_certificates,omitempty"` @@ -95,12 +96,12 @@ func getPluginsAssociatedWithCACertSecret(secretID string, storer store.Storer) } var affectedPlugins []client.Object - for _, p := range storer.ListKongPlugins() { + for _, p := range storer.ListKongPlugins(ctx) { if refersToSecret(p.Config) { affectedPlugins = append(affectedPlugins, p.DeepCopy()) } } - for _, p := range storer.ListKongClusterPlugins() { + for _, p := range storer.ListKongClusterPlugins(ctx) { if refersToSecret(p.Config) { affectedPlugins = append(affectedPlugins, p.DeepCopy()) } diff --git a/internal/dataplane/parser/translate_secrets_test.go b/internal/dataplane/parser/translate_secrets_test.go index f5e82cb2e7..91d5e2da3e 100644 --- a/internal/dataplane/parser/translate_secrets_test.go +++ b/internal/dataplane/parser/translate_secrets_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" "testing" @@ -53,7 +54,7 @@ func TestGetPluginsAssociatedWithCACertSecret(t *testing.T) { }) require.NoError(t, err) - gotPlugins := getPluginsAssociatedWithCACertSecret(secretID, storer) + gotPlugins := getPluginsAssociatedWithCACertSecret(context.TODO(), secretID, storer) //nolint:contextcheck expectedPlugins := []client.Object{associatedPlugin, associatedClusterPlugin} require.ElementsMatch(t, expectedPlugins, gotPlugins, "expected plugins do not match actual ones") } diff --git a/internal/store/fake_store.go b/internal/store/fake_store.go index 8944291d65..143a8f9049 100644 --- a/internal/store/fake_store.go +++ b/internal/store/fake_store.go @@ -250,13 +250,7 @@ func NewFakeStore( Gateway: gatewayStore, TCPIngress: tcpIngressStore, UDPIngress: udpIngressStore, - Service: serviceStore, - Endpoint: endpointStore, - Secret: secretsStore, - Plugin: kongPluginsStore, - ClusterPlugin: kongClusterPluginsStore, - Consumer: consumerStore, KongIngress: kongIngressStore, IngressClassParametersV1alpha1: IngressClassParametersV1alpha1Store, diff --git a/internal/store/fake_store_test.go b/internal/store/fake_store_test.go index b3b0c84a88..9e2554560d 100644 --- a/internal/store/fake_store_test.go +++ b/internal/store/fake_store_test.go @@ -464,11 +464,11 @@ func TestFakeStoreService(t *testing.T) { store, err := NewFakeStore(FakeObjects{Services: services}) require.Nil(err) require.NotNil(store) - service, err := store.GetService("default", "foo") + service, err := store.GetService(context.TODO(), "default", "foo") //nolint:contextcheck assert.NotNil(service) assert.Nil(err) - service, err = store.GetService("default", "does-not-exists") + service, err = store.GetService(context.TODO(), "default", "does-not-exists") //nolint:contextcheck assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(service) @@ -489,11 +489,11 @@ func TestFakeStoreEndpiont(t *testing.T) { store, err := NewFakeStore(FakeObjects{Endpoints: endpoints}) require.Nil(err) require.NotNil(store) - c, err := store.GetEndpointsForService("default", "foo") + c, err := store.GetEndpointsForService(context.TODO(), "default", "foo") //nolint:contextcheck assert.Nil(err) assert.NotNil(c) - c, err = store.GetEndpointsForService("default", "does-not-exist") + c, err = store.GetEndpointsForService(context.TODO(), "default", "does-not-exist") //nolint:contextcheck assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(c) @@ -517,12 +517,12 @@ func TestFakeStoreConsumer(t *testing.T) { store, err := NewFakeStore(FakeObjects{KongConsumers: consumers}) require.Nil(err) require.NotNil(store) - assert.Len(store.ListKongConsumers(), 1) - c, err := store.GetKongConsumer("default", "foo") + assert.Len(store.ListKongConsumers(context.TODO()), 1) //nolint:contextcheck + c, err := store.GetKongConsumer(context.TODO(), "default", "foo") //nolint:contextcheck assert.Nil(err) assert.NotNil(c) - c, err = store.GetKongConsumer("default", "does-not-exist") + c, err = store.GetKongConsumer(context.TODO(), "default", "does-not-exist") //nolint:contextcheck assert.Nil(c) assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) @@ -555,11 +555,11 @@ func TestFakeStorePlugins(t *testing.T) { store, err = NewFakeStore(FakeObjects{KongPlugins: plugins}) require.Nil(err) require.NotNil(store) - plugins, err = store.ListGlobalKongPlugins() + plugins, err = store.ListGlobalKongPlugins(context.TODO()) //nolint:contextcheck assert.NoError(err) assert.Len(plugins, 0) - plugin, err := store.GetKongPlugin("default", "does-not-exist") + plugin, err := store.GetKongPlugin(context.TODO(), "default", "does-not-exist") //nolint:contextcheck assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(plugin) @@ -579,7 +579,7 @@ func TestFakeStoreClusterPlugins(t *testing.T) { store, err := NewFakeStore(FakeObjects{KongClusterPlugins: plugins}) require.Nil(err) require.NotNil(store) - plugins, err = store.ListGlobalKongClusterPlugins() + plugins, err = store.ListGlobalKongClusterPlugins(context.TODO()) //nolint:contextcheck assert.NoError(err) assert.Len(plugins, 0) @@ -613,15 +613,15 @@ func TestFakeStoreClusterPlugins(t *testing.T) { store, err = NewFakeStore(FakeObjects{KongClusterPlugins: plugins}) require.Nil(err) require.NotNil(store) - plugins, err = store.ListGlobalKongClusterPlugins() + plugins, err = store.ListGlobalKongClusterPlugins(context.TODO()) //nolint:contextcheck assert.NoError(err) assert.Len(plugins, 1) - plugin, err := store.GetKongClusterPlugin("foo") + plugin, err := store.GetKongClusterPlugin(context.TODO(), "foo") //nolint:contextcheck assert.NotNil(plugin) assert.Nil(err) - plugin, err = store.GetKongClusterPlugin("does-not-exist") + plugin, err = store.GetKongClusterPlugin(context.TODO(), "does-not-exist") //nolint:contextcheck assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(plugin) @@ -642,11 +642,11 @@ func TestFakeStoreSecret(t *testing.T) { store, err := NewFakeStore(FakeObjects{Secrets: secrets}) require.Nil(err) require.NotNil(store) - secret, err := store.GetSecret("default", "foo") + secret, err := store.GetSecret(context.TODO(), "default", "foo") //nolint:contextcheck assert.Nil(err) assert.NotNil(secret) - secret, err = store.GetSecret("default", "does-not-exist") + secret, err = store.GetSecret(context.TODO(), "default", "does-not-exist") //nolint:contextcheck assert.Nil(secret) assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) @@ -692,7 +692,7 @@ func TestFakeStore_ListCACerts(t *testing.T) { store, err := NewFakeStore(FakeObjects{Secrets: secrets}) require.Nil(err) require.NotNil(store) - certs, err := store.ListCACerts() + certs, err := store.ListCACerts(context.TODO()) //nolint:contextcheck assert.Nil(err) assert.Len(certs, 0) @@ -725,7 +725,7 @@ func TestFakeStore_ListCACerts(t *testing.T) { store, err = NewFakeStore(FakeObjects{Secrets: secrets}) require.Nil(err) require.NotNil(store) - certs, err = store.ListCACerts() + certs, err = store.ListCACerts(context.TODO()) //nolint:contextcheck assert.Nil(err) assert.Len(certs, 2, "expect two secrets as CA certificates") } diff --git a/internal/store/store.go b/internal/store/store.go index 3e4ed94962..c4bdc0656b 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -24,8 +24,10 @@ import ( "strings" "sync" + "github.com/samber/lo" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" netv1beta1 "k8s.io/api/networking/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -73,13 +75,13 @@ func (e ErrNotFound) Error() string { // Storer is the interface that wraps the required methods to gather information // about ingresses, services, secrets and ingress annotations. type Storer interface { - GetSecret(namespace, name string) (*corev1.Secret, error) - GetService(namespace, name string) (*corev1.Service, error) - GetEndpointsForService(namespace, name string) (*corev1.Endpoints, error) + GetSecret(ctx context.Context, namespace, name string) (*corev1.Secret, error) + GetService(ctx context.Context, namespace, name string) (*corev1.Service, error) + GetEndpointsForService(ctx context.Context, namespace, name string) (*corev1.Endpoints, error) GetKongIngress(namespace, name string) (*kongv1.KongIngress, error) - GetKongPlugin(namespace, name string) (*kongv1.KongPlugin, error) - GetKongClusterPlugin(name string) (*kongv1.KongClusterPlugin, error) - GetKongConsumer(namespace, name string) (*kongv1.KongConsumer, error) + GetKongPlugin(ctx context.Context, namespace, name string) (*kongv1.KongPlugin, error) + GetKongClusterPlugin(ctx context.Context, name string) (*kongv1.KongClusterPlugin, error) + GetKongConsumer(ctx context.Context, namespace, name string) (*kongv1.KongConsumer, error) GetIngressClassName() string GetIngressClassV1(ctx context.Context, name string) (*netv1.IngressClass, error) GetIngressClassParametersV1Alpha1(ingressClass *netv1.IngressClass) (*kongv1alpha1.IngressClassParameters, error) @@ -99,12 +101,12 @@ type Storer interface { ListTCPIngresses() ([]*kongv1beta1.TCPIngress, error) ListUDPIngresses() ([]*kongv1beta1.UDPIngress, error) ListKnativeIngresses() ([]*knative.Ingress, error) - ListGlobalKongPlugins() ([]*kongv1.KongPlugin, error) - ListGlobalKongClusterPlugins() ([]*kongv1.KongClusterPlugin, error) - ListKongPlugins() []*kongv1.KongPlugin - ListKongClusterPlugins() []*kongv1.KongClusterPlugin - ListKongConsumers() []*kongv1.KongConsumer - ListCACerts() ([]*corev1.Secret, error) + ListGlobalKongPlugins(ctx context.Context) ([]*kongv1.KongPlugin, error) + ListGlobalKongClusterPlugins(ctx context.Context) ([]*kongv1.KongClusterPlugin, error) + ListKongPlugins(ctx context.Context) []*kongv1.KongPlugin + ListKongClusterPlugins(ctx context.Context) []*kongv1.KongClusterPlugin + ListKongConsumers(ctx context.Context) []*kongv1.KongConsumer + ListCACerts(ctx context.Context) ([]*corev1.Secret, error) } // Store implements Storer and can be used to list Ingress, Services @@ -131,9 +133,6 @@ var _ Storer = Store{} // the Ingress Controller reads. type CacheStores struct { // Core Kubernetes Stores - Service cache.Store - Secret cache.Store - Endpoint cache.Store // Gateway API Stores HTTPRoute cache.Store @@ -145,9 +144,6 @@ type CacheStores struct { Gateway cache.Store // Kong Stores - Plugin cache.Store - ClusterPlugin cache.Store - Consumer cache.Store KongIngress cache.Store TCPIngress cache.Store UDPIngress cache.Store @@ -167,9 +163,6 @@ func NewCacheStores(client client.Client) CacheStores { client: client, // Core Kubernetes Stores - Service: cache.NewStore(keyFunc), - Secret: cache.NewStore(keyFunc), - Endpoint: cache.NewStore(keyFunc), // Gateway API Stores HTTPRoute: cache.NewStore(keyFunc), UDPRoute: cache.NewStore(keyFunc), @@ -179,9 +172,6 @@ func NewCacheStores(client client.Client) CacheStores { ReferenceGrant: cache.NewStore(keyFunc), Gateway: cache.NewStore(keyFunc), // Kong Stores - Plugin: cache.NewStore(keyFunc), - ClusterPlugin: cache.NewStore(clusterResourceKeyFunc), - Consumer: cache.NewStore(keyFunc), KongIngress: cache.NewStore(keyFunc), TCPIngress: cache.NewStore(keyFunc), UDPIngress: cache.NewStore(keyFunc), @@ -244,12 +234,6 @@ func (c CacheStores) Get(obj runtime.Object) (item interface{}, exists bool, err // ---------------------------------------------------------------------------- // Kubernetes Core API Support // ---------------------------------------------------------------------------- - case *corev1.Service: - return c.Service.Get(obj) - case *corev1.Secret: - return c.Secret.Get(obj) - case *corev1.Endpoints: - return c.Endpoint.Get(obj) // ---------------------------------------------------------------------------- // Kubernetes Gateway API Support // ---------------------------------------------------------------------------- @@ -270,12 +254,6 @@ func (c CacheStores) Get(obj runtime.Object) (item interface{}, exists bool, err // ---------------------------------------------------------------------------- // Kong API Support // ---------------------------------------------------------------------------- - case *kongv1.KongPlugin: - return c.Plugin.Get(obj) - case *kongv1.KongClusterPlugin: - return c.ClusterPlugin.Get(obj) - case *kongv1.KongConsumer: - return c.Consumer.Get(obj) case *kongv1.KongIngress: return c.KongIngress.Get(obj) case *kongv1beta1.TCPIngress: @@ -303,12 +281,6 @@ func (c CacheStores) Add(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kubernetes Core API Support // ---------------------------------------------------------------------------- - case *corev1.Service: - return c.Service.Add(obj) - case *corev1.Secret: - return c.Secret.Add(obj) - case *corev1.Endpoints: - return c.Endpoint.Add(obj) // ---------------------------------------------------------------------------- // Kubernetes Gateway API Support // ---------------------------------------------------------------------------- @@ -329,12 +301,6 @@ func (c CacheStores) Add(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kong API Support // ---------------------------------------------------------------------------- - case *kongv1.KongPlugin: - return c.Plugin.Add(obj) - case *kongv1.KongClusterPlugin: - return c.ClusterPlugin.Add(obj) - case *kongv1.KongConsumer: - return c.Consumer.Add(obj) case *kongv1.KongIngress: return c.KongIngress.Add(obj) case *kongv1beta1.TCPIngress: @@ -363,13 +329,6 @@ func (c CacheStores) Delete(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kubernetes Core API Support // ---------------------------------------------------------------------------- - - case *corev1.Service: - return c.Service.Delete(obj) - case *corev1.Secret: - return c.Secret.Delete(obj) - case *corev1.Endpoints: - return c.Endpoint.Delete(obj) // ---------------------------------------------------------------------------- // Kubernetes Gateway API Support // ---------------------------------------------------------------------------- @@ -390,12 +349,6 @@ func (c CacheStores) Delete(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kong API Support // ---------------------------------------------------------------------------- - case *kongv1.KongPlugin: - return c.Plugin.Delete(obj) - case *kongv1.KongClusterPlugin: - return c.ClusterPlugin.Delete(obj) - case *kongv1.KongConsumer: - return c.Consumer.Delete(obj) case *kongv1.KongIngress: return c.KongIngress.Delete(obj) case *kongv1beta1.TCPIngress: @@ -428,29 +381,37 @@ func New(client client.Client, cs CacheStores, ingressClass string, logger logru } // GetSecret returns a Secret using the namespace and name as key. -func (s Store) GetSecret(namespace, name string) (*corev1.Secret, error) { - key := fmt.Sprintf("%v/%v", namespace, name) - secret, exists, err := s.stores.Secret.GetByKey(key) +func (s Store) GetSecret(ctx context.Context, namespace, name string) (*corev1.Secret, error) { + key := client.ObjectKey{ + Namespace: namespace, + Name: name, + } + var secret corev1.Secret + err := s.client.Get(ctx, key, &secret) if err != nil { return nil, err } - if !exists { - return nil, ErrNotFound{fmt.Sprintf("Secret %v not found", key)} + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("Secret %v not found", name)} } - return secret.(*corev1.Secret), nil + return &secret, nil } // GetService returns a Service using the namespace and name as key. -func (s Store) GetService(namespace, name string) (*corev1.Service, error) { - key := fmt.Sprintf("%v/%v", namespace, name) - service, exists, err := s.stores.Service.GetByKey(key) +func (s Store) GetService(ctx context.Context, namespace, name string) (*corev1.Service, error) { + key := client.ObjectKey{ + Namespace: namespace, + Name: name, + } + var svc v1.Service + err := s.client.Get(ctx, key, &svc) if err != nil { return nil, err } - if !exists { - return nil, ErrNotFound{fmt.Sprintf("Service %v not found", key)} + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("Service %v not found", name)} } - return service.(*corev1.Service), nil + return &svc, nil } // ListIngressesV1 returns the list of Ingresses in the Ingress v1 store. @@ -745,43 +706,63 @@ func (s Store) ListKnativeIngresses() ([]*knative.Ingress, error) { return ingresses, nil } -// GetEndpointsForService returns the internal endpoints for service -// 'namespace/name' inside k8s. -func (s Store) GetEndpointsForService(namespace, name string) (*corev1.Endpoints, error) { - key := fmt.Sprintf("%v/%v", namespace, name) - eps, exists, err := s.stores.Endpoint.GetByKey(key) +// GetEndpointsForService returns the internal endpoints for service 'namespace/name' inside k8s. +func (s Store) GetEndpointsForService(ctx context.Context, namespace, name string) (*corev1.Endpoints, error) { + var ( + endpoints corev1.Endpoints + key = client.ObjectKey{ + Namespace: namespace, + Name: name, + } + ) + + err := s.client.Get(ctx, key, &endpoints) if err != nil { return nil, err } - if !exists { + if apierrors.IsNotFound(err) { return nil, ErrNotFound{fmt.Sprintf("Endpoints for service %v not found", key)} } - return eps.(*corev1.Endpoints), nil + return &endpoints, nil } // GetKongPlugin returns the 'name' KongPlugin resource in namespace. -func (s Store) GetKongPlugin(namespace, name string) (*kongv1.KongPlugin, error) { - key := fmt.Sprintf("%v/%v", namespace, name) - p, exists, err := s.stores.Plugin.GetByKey(key) +func (s Store) GetKongPlugin(ctx context.Context, namespace, name string) (*kongv1.KongPlugin, error) { + var ( + plugin kongv1.KongPlugin + key = client.ObjectKey{ + Namespace: namespace, + Name: name, + } + ) + + err := s.client.Get(ctx, key, &plugin) if err != nil { return nil, err } - if !exists { + if apierrors.IsNotFound(err) { return nil, ErrNotFound{fmt.Sprintf("KongPlugin %v not found", key)} } - return p.(*kongv1.KongPlugin), nil + return &plugin, nil } // GetKongClusterPlugin returns the 'name' KongClusterPlugin resource. -func (s Store) GetKongClusterPlugin(name string) (*kongv1.KongClusterPlugin, error) { - p, exists, err := s.stores.ClusterPlugin.GetByKey(name) +func (s Store) GetKongClusterPlugin(ctx context.Context, name string) (*kongv1.KongClusterPlugin, error) { + var ( + plugin kongv1.KongClusterPlugin + key = client.ObjectKey{ + Name: name, + } + ) + + err := s.client.Get(ctx, key, &plugin) if err != nil { return nil, err } - if !exists { - return nil, ErrNotFound{fmt.Sprintf("KongClusterPlugin %v not found", name)} + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("KongClusterPlugin %v not found", key)} } - return p.(*kongv1.KongClusterPlugin), nil + return &plugin, nil } // GetKongIngress returns the 'name' KongIngress resource in namespace. @@ -798,16 +779,23 @@ func (s Store) GetKongIngress(namespace, name string) (*kongv1.KongIngress, erro } // GetKongConsumer returns the 'name' KongConsumer resource in namespace. -func (s Store) GetKongConsumer(namespace, name string) (*kongv1.KongConsumer, error) { - key := fmt.Sprintf("%v/%v", namespace, name) - p, exists, err := s.stores.Consumer.GetByKey(key) +func (s Store) GetKongConsumer(ctx context.Context, namespace, name string) (*kongv1.KongConsumer, error) { + var ( + consumer kongv1.KongConsumer + key = client.ObjectKey{ + Namespace: namespace, + Name: name, + } + ) + + err := s.client.Get(ctx, key, &consumer) if err != nil { return nil, err } - if !exists { + if apierrors.IsNotFound(err) { return nil, ErrNotFound{fmt.Sprintf("KongConsumer %v not found", key)} } - return p.(*kongv1.KongConsumer), nil + return &consumer, nil } func (s Store) GetIngressClassName() string { @@ -891,15 +879,21 @@ func (s Store) GetGateway(namespace string, name string) (*gatewayv1beta1.Gatewa // ListKongConsumers returns all KongConsumers filtered by the ingress.class // annotation. -func (s Store) ListKongConsumers() []*kongv1.KongConsumer { - var consumers []*kongv1.KongConsumer - for _, item := range s.stores.Consumer.List() { - c, ok := item.(*kongv1.KongConsumer) - if ok && s.isValidIngressClass(&c.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { - consumers = append(consumers, c) - } +func (s Store) ListKongConsumers(ctx context.Context) []*kongv1.KongConsumer { + var ( + consumers []*kongv1.KongConsumer + consumerList kongv1.KongConsumerList + ) + if err := s.client.List(ctx, &consumerList); err != nil { + return nil } + for i := range consumerList.Items { + plugin := consumerList.Items[i] + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + consumers = append(consumers, &plugin) + } + } return consumers } @@ -908,94 +902,122 @@ func (s Store) ListKongConsumers() []*kongv1.KongConsumer { // label global:"true". // Support for these global namespaced KongPlugins was removed in 0.10.0 // This function remains only to provide warnings to users with old configuration. -func (s Store) ListGlobalKongPlugins() ([]*kongv1.KongPlugin, error) { - var plugins []*kongv1.KongPlugin +func (s Store) ListGlobalKongPlugins(ctx context.Context) ([]*kongv1.KongPlugin, error) { req, err := labels.NewRequirement("global", selection.Equals, []string{"true"}) if err != nil { return nil, err } - err = cache.ListAll(s.stores.Plugin, - labels.NewSelector().Add(*req), - func(ob interface{}) { - p, ok := ob.(*kongv1.KongPlugin) - if ok && s.isValidIngressClass(&p.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { - plugins = append(plugins, p) - } - }) + + var ( + plugins []*kongv1.KongPlugin + pluginList kongv1.KongPluginList + ) + err = s.client.List(ctx, &pluginList, &client.ListOptions{ + LabelSelector: labels.NewSelector().Add(*req), + }) if err != nil { return nil, err } + + for i := range pluginList.Items { + plugin := pluginList.Items[i] + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + plugins = append(plugins, &plugin) + } + } + return plugins, nil } // ListGlobalKongClusterPlugins returns all KongClusterPlugin resources // filtered by the ingress.class annotation and with the // label global:"true". -func (s Store) ListGlobalKongClusterPlugins() ([]*kongv1.KongClusterPlugin, error) { - var plugins []*kongv1.KongClusterPlugin - +func (s Store) ListGlobalKongClusterPlugins(ctx context.Context) ([]*kongv1.KongClusterPlugin, error) { req, err := labels.NewRequirement("global", selection.Equals, []string{"true"}) if err != nil { return nil, err } - err = cache.ListAll(s.stores.ClusterPlugin, - labels.NewSelector().Add(*req), - func(ob interface{}) { - p, ok := ob.(*kongv1.KongClusterPlugin) - if ok && s.isValidIngressClass(&p.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { - plugins = append(plugins, p) - } - }) + + var ( + plugins []*kongv1.KongClusterPlugin + pluginList kongv1.KongClusterPluginList + ) + err = s.client.List(ctx, &pluginList, &client.ListOptions{ + LabelSelector: labels.NewSelector().Add(*req), + }) if err != nil { return nil, err } + + for i := range pluginList.Items { + plugin := pluginList.Items[i] + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + plugins = append(plugins, &plugin) + } + } + return plugins, nil } // ListKongClusterPlugins lists all KongClusterPlugins that match expected ingress.class annotation. -func (s Store) ListKongClusterPlugins() []*kongv1.KongClusterPlugin { - var plugins []*kongv1.KongClusterPlugin - for _, item := range s.stores.ClusterPlugin.List() { - p, ok := item.(*kongv1.KongClusterPlugin) - if ok && s.isValidIngressClass(&p.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { - plugins = append(plugins, p) +func (s Store) ListKongClusterPlugins(ctx context.Context) []*kongv1.KongClusterPlugin { + var ( + plugins []*kongv1.KongClusterPlugin + pluginList kongv1.KongClusterPluginList + ) + if err := s.client.List(ctx, &pluginList); err != nil { + return nil + } + + for i := range pluginList.Items { + plugin := pluginList.Items[i] + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + plugins = append(plugins, &plugin) } } + return plugins } // ListKongPlugins lists all KongPlugins. -func (s Store) ListKongPlugins() []*kongv1.KongPlugin { - var plugins []*kongv1.KongPlugin - for _, item := range s.stores.Plugin.List() { - p, ok := item.(*kongv1.KongPlugin) - if ok { - plugins = append(plugins, p) - } +func (s Store) ListKongPlugins(ctx context.Context) []*kongv1.KongPlugin { + var pluginList kongv1.KongPluginList + if err := s.client.List(ctx, &pluginList); err != nil { + return nil } - return plugins + + return lo.Map(pluginList.Items, + func(p kongv1.KongPlugin, _ int) *kongv1.KongPlugin { + return &p + }) } // ListCACerts returns all Secrets containing the label // "konghq.com/ca-cert"="true". -func (s Store) ListCACerts() ([]*corev1.Secret, error) { - var secrets []*corev1.Secret - req, err := labels.NewRequirement(caCertKey, - selection.Equals, []string{"true"}) +func (s Store) ListCACerts(ctx context.Context) ([]*corev1.Secret, error) { + req, err := labels.NewRequirement(caCertKey, selection.Equals, []string{"true"}) if err != nil { return nil, err } - err = cache.ListAll(s.stores.Secret, - labels.NewSelector().Add(*req), - func(ob interface{}) { - p, ok := ob.(*corev1.Secret) - if ok && s.isValidIngressClass(&p.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { - secrets = append(secrets, p) - } - }) + + var ( + secrets []*corev1.Secret + secretList corev1.SecretList + ) + err = s.client.List(context.TODO(), &secretList, &client.ListOptions{ + LabelSelector: labels.NewSelector().Add(*req), + }) if err != nil { return nil, err } + + for i := range secretList.Items { + secret := secretList.Items[i] + if s.isValidIngressClass(&secret.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + secrets = append(secrets, &secret) + } + } + return secrets, nil } diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 51016db5a1..322cc146c3 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -119,8 +119,9 @@ spec: assert.False(t, exists) t.Log("verifying the integrity of the cache store") + // TODO(pmalek) // assert.Len(t, cs.IngressV1.List(), 1) - assert.Len(t, cs.Service.List(), 1) + // assert.Len(t, cs.Service.List(), 1) // assert.Len(t, cs.IngressV1beta1.List(), 0) assert.Len(t, cs.KongIngress.List(), 0) _, exists, err = cs.Get(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: "doesntexist", Name: "doesntexist"}}) From d8e16c66107253d328171ca14f44e87e2ecaa0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Thu, 6 Apr 2023 14:46:38 +0200 Subject: [PATCH 3/4] wip3 --- internal/adminapi/kong.go | 2 +- internal/controllers/gateway/route_utils.go | 2 +- internal/dataplane/kong_client.go | 25 +- internal/dataplane/kongstate/kongstate.go | 10 +- .../dataplane/kongstate/kongstate_test.go | 2 +- internal/dataplane/kongstate/util.go | 11 +- internal/dataplane/kongstate/util_test.go | 8 +- .../parser/ingressclassparemeters_test.go | 13 +- .../dataplane/parser/ingressrules_test.go | 4 +- internal/dataplane/parser/parser.go | 28 +- internal/dataplane/parser/parser_test.go | 6 +- .../dataplane/parser/translate_grpcroute.go | 11 +- .../dataplane/parser/translate_httproute.go | 21 +- .../parser/translate_httproute_test.go | 7 +- .../dataplane/parser/translate_knative.go | 6 +- .../parser/translate_knative_test.go | 13 +- .../dataplane/parser/translate_kong_l4.go | 9 +- .../parser/translate_kong_l4_test.go | 11 +- .../parser/translate_secrets_test.go | 2 +- .../dataplane/parser/translate_tcproute.go | 11 +- .../dataplane/parser/translate_tlsroute.go | 17 +- .../dataplane/parser/translate_udproute.go | 11 +- internal/dataplane/parser/translate_utils.go | 6 +- .../dataplane/parser/translate_utils_test.go | 3 +- internal/store/fake_store.go | 18 +- internal/store/fake_store_test.go | 54 +- internal/store/store.go | 679 ++++++++---------- internal/store/store_test.go | 80 +-- 28 files changed, 452 insertions(+), 618 deletions(-) diff --git a/internal/adminapi/kong.go b/internal/adminapi/kong.go index 1c263db0d3..0f01275243 100644 --- a/internal/adminapi/kong.go +++ b/internal/adminapi/kong.go @@ -78,7 +78,7 @@ func MakeHTTPClient(opts *HTTPClientOpts, kongAdminToken string) (*http.Client, var tlsConfig tls.Config if opts.TLSSkipVerify { - tlsConfig.InsecureSkipVerify = true + tlsConfig.InsecureSkipVerify = true } if opts.TLSServerName != "" { diff --git a/internal/controllers/gateway/route_utils.go b/internal/controllers/gateway/route_utils.go index c119b288b5..746ce009d5 100644 --- a/internal/controllers/gateway/route_utils.go +++ b/internal/controllers/gateway/route_utils.go @@ -227,7 +227,7 @@ func getSupportedGatewayForRoute[T types.RouteT](ctx context.Context, mgrc clien // - And finally check if that listeners is marked as Ready. if err := existsMatchingReadyListenerInStatus(route, listener, gateway.Status.Listeners); err != nil { continue - } else { + } else { //nolint:revive allowedBySupportedKinds = true } diff --git a/internal/dataplane/kong_client.go b/internal/dataplane/kong_client.go index 835a815253..625ac165c9 100644 --- a/internal/dataplane/kong_client.go +++ b/internal/dataplane/kong_client.go @@ -16,6 +16,7 @@ import ( "golang.org/x/exp/slices" "golang.org/x/sync/errgroup" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" @@ -185,25 +186,29 @@ func NewKongClient( // It will be asynchronously converted into the upstream Kong DSL and applied to the Kong Admin API. // A status will later be added to the object whether the configuration update succeeds or fails. func (c *KongClient) UpdateObject(obj client.Object) error { - // we do a deep copy of the object here so that the caller can continue to use - // the original object in a threadsafe manner. - return c.cache.Add(obj.DeepCopyObject()) + return c.client.Update(context.TODO(), obj) } -// DeleteObject accepts a Kubernetes controller-runtime client.Object and removes it from the configuration cache. +// DeleteObject accepts a Kubernetes controller-runtime client.Object and removes it from the configuration. // The delete action will asynchronously be converted to Kong DSL and applied to the Kong Admin API. // A status will later be added to the object whether the configuration update succeeds or fails. // -// under the hood the cache implementation will ignore deletions on objects -// that are not present in the cache, so in those cases this is a no-op. +// The implementation will ignore deletions on objects that are not present, so in those cases this is a no-op. func (c *KongClient) DeleteObject(obj client.Object) error { - return c.cache.Delete(obj) + err := c.client.Delete(context.TODO(), obj) + if apierrors.IsNotFound(err) { + return nil + } + return err } // ObjectExists indicates whether or not any version of the provided object is already present in the proxy. func (c *KongClient) ObjectExists(obj client.Object) (bool, error) { - _, exists, err := c.cache.Get(obj) - return exists, err + err := c.client.Get(context.TODO(), client.ObjectKeyFromObject(obj), obj) + if apierrors.IsNotFound(err) { + return false, err + } + return true, nil } // allEqual returns true if all provided objects are equal. @@ -393,7 +398,7 @@ func (c *KongClient) Update(ctx context.Context) error { defer c.lock.Unlock() // build the kongstate object from the Kubernetes objects in the storer - storer := store.New(c.client, *c.cache, c.ingressClass, c.logger) + storer := store.New(c.client, c.ingressClass, c.logger) // initialize a parser c.logger.Debug("parsing kubernetes objects into data-plane configuration") diff --git a/internal/dataplane/kongstate/kongstate.go b/internal/dataplane/kongstate/kongstate.go index 86f3f44506..c21b7863e3 100644 --- a/internal/dataplane/kongstate/kongstate.go +++ b/internal/dataplane/kongstate/kongstate.go @@ -76,7 +76,7 @@ func (ks *KongState) FillConsumersAndCredentials(ctx context.Context, log logrus "secret_name": cred, "secret_namespace": consumer.Namespace, }) - secret, err := s.GetSecret(ctx, consumer.Namespace, cred) //nolint:contextcheck + secret, err := s.GetSecret(ctx, consumer.Namespace, cred) if err != nil { log.WithError(err).Error("failed to fetch secret") continue @@ -146,10 +146,10 @@ func (ks *KongState) FillConsumersAndCredentials(ctx context.Context, log logrus } } -func (ks *KongState) FillOverrides(log logrus.FieldLogger, s store.Storer) { +func (ks *KongState) FillOverrides(ctx context.Context, log logrus.FieldLogger, s store.Storer) { for i := 0; i < len(ks.Services); i++ { // Services - kongIngress, err := getKongIngressForServices(s, ks.Services[i].K8sServices) + kongIngress, err := getKongIngressForServices(ctx, s, ks.Services[i].K8sServices) if err != nil { log.WithError(err). Errorf("failed to fetch KongIngress resource for Services %s", @@ -164,7 +164,7 @@ func (ks *KongState) FillOverrides(log logrus.FieldLogger, s store.Storer) { // Routes for j := 0; j < len(ks.Services[i].Routes); j++ { - kongIngress, err := getKongIngressFromObjectMeta(s, ks.Services[i].Routes[j].Ingress) + kongIngress, err := getKongIngressFromObjectMeta(ctx, s, ks.Services[i].Routes[j].Ingress) if err != nil { log.WithFields(logrus.Fields{ "resource_name": ks.Services[i].Routes[j].Ingress.Name, @@ -178,7 +178,7 @@ func (ks *KongState) FillOverrides(log logrus.FieldLogger, s store.Storer) { // Upstreams for i := 0; i < len(ks.Upstreams); i++ { - kongIngress, err := getKongIngressForServices(s, ks.Upstreams[i].Service.K8sServices) + kongIngress, err := getKongIngressForServices(ctx, s, ks.Upstreams[i].Service.K8sServices) if err != nil { log.WithError(err). Errorf("failed to fetch KongIngress resource for Services %s", diff --git a/internal/dataplane/kongstate/kongstate_test.go b/internal/dataplane/kongstate/kongstate_test.go index 5a93db8d80..0648319d0e 100644 --- a/internal/dataplane/kongstate/kongstate_test.go +++ b/internal/dataplane/kongstate/kongstate_test.go @@ -387,7 +387,7 @@ func TestFillConsumersAndCredentials(t *testing.T) { state := KongState{ Version: semver.MustParse("2.3.2"), } - state.FillConsumersAndCredentials(context.TODO(), logrus.New(), store) //nolint:contextcheck + state.FillConsumersAndCredentials(context.TODO(), logrus.New(), store) assert.Equal(t, want.Consumers[0].Consumer.Username, state.Consumers[0].Consumer.Username) assert.Equal(t, want.Consumers[0].Consumer.CustomID, state.Consumers[0].Consumer.CustomID) assert.Equal(t, want.Consumers[0].KeyAuths[0].Key, state.Consumers[0].KeyAuths[0].Key) diff --git a/internal/dataplane/kongstate/util.go b/internal/dataplane/kongstate/util.go index b70d510627..34ad4ea785 100644 --- a/internal/dataplane/kongstate/util.go +++ b/internal/dataplane/kongstate/util.go @@ -18,6 +18,7 @@ import ( ) func getKongIngressForServices( + ctx context.Context, s store.Storer, services map[string]*corev1.Service, ) (*configurationv1.KongIngress, error) { @@ -34,7 +35,7 @@ func getKongIngressForServices( } // retrieve the attached KongIngress for the service - kongIngress, err := s.GetKongIngress(svc.Namespace, confName) + kongIngress, err := s.GetKongIngress(ctx, svc.Namespace, confName) if err != nil { return nil, err } @@ -50,15 +51,17 @@ func getKongIngressForServices( } func getKongIngressFromObjectMeta( + ctx context.Context, s store.Storer, obj util.K8sObjectInfo, ) ( *configurationv1.KongIngress, error, ) { - return getKongIngressFromObjAnnotations(s, obj) + return getKongIngressFromObjAnnotations(ctx, s, obj) } func getKongIngressFromObjAnnotations( + ctx context.Context, s store.Storer, obj util.K8sObjectInfo, ) ( @@ -66,13 +69,13 @@ func getKongIngressFromObjAnnotations( ) { confName := annotations.ExtractConfigurationName(obj.Annotations) if confName != "" { - ki, err := s.GetKongIngress(obj.Namespace, confName) + ki, err := s.GetKongIngress(ctx, obj.Namespace, confName) if err == nil { return ki, nil } } - ki, err := s.GetKongIngress(obj.Namespace, obj.Name) + ki, err := s.GetKongIngress(ctx, obj.Namespace, obj.Name) if err == nil { return ki, nil } diff --git a/internal/dataplane/kongstate/util_test.go b/internal/dataplane/kongstate/util_test.go index 953a4d7d26..25e55b8384 100644 --- a/internal/dataplane/kongstate/util_test.go +++ b/internal/dataplane/kongstate/util_test.go @@ -146,7 +146,7 @@ func TestKongPluginFromK8SClusterPlugin(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := kongPluginFromK8SClusterPlugin(context.TODO(), store, tt.args.plugin) //nolint:contextcheck + got, err := kongPluginFromK8SClusterPlugin(context.TODO(), store, tt.args.plugin) if (err != nil) != tt.wantErr { t.Errorf("kongPluginFromK8SClusterPlugin error = %v, wantErr %v", err, tt.wantErr) return @@ -285,7 +285,7 @@ func TestKongPluginFromK8SPlugin(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := kongPluginFromK8SPlugin(context.TODO(), store, tt.args.plugin) //nolint:contextcheck + got, err := kongPluginFromK8SPlugin(context.TODO(), store, tt.args.plugin) if (err != nil) != tt.wantErr { t.Errorf("kongPluginFromK8SPlugin error = %v, wantErr %v", err, tt.wantErr) return @@ -447,7 +447,7 @@ func TestGetKongIngressForServices(t *testing.T) { }) require.NoError(t, err) - kongIngress, err := getKongIngressForServices(storer, tt.services) + kongIngress, err := getKongIngressForServices(context.TODO(), storer, tt.services) if tt.expectedError == nil { assert.Equal(t, tt.expectedKongIngress, kongIngress) } else { @@ -574,7 +574,7 @@ func TestGetKongIngressFromObjectMeta(t *testing.T) { require.NoError(t, err) obj := util.FromK8sObject(tt.route) - kongIngress, err := getKongIngressFromObjectMeta(storer, obj) + kongIngress, err := getKongIngressFromObjectMeta(context.TODO(), storer, obj) if tt.expectedError == nil { require.NoError(t, err) diff --git a/internal/dataplane/parser/ingressclassparemeters_test.go b/internal/dataplane/parser/ingressclassparemeters_test.go index a48d080b51..da74073db2 100644 --- a/internal/dataplane/parser/ingressclassparemeters_test.go +++ b/internal/dataplane/parser/ingressclassparemeters_test.go @@ -12,10 +12,12 @@ import ( "github.com/stretchr/testify/require" netv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" configurationv1alpha1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1alpha1" + "github.com/kong/kubernetes-ingress-controller/v2/pkg/clientset/fake" ) func TestGetIngressClassParameters(t *testing.T) { @@ -143,18 +145,15 @@ func TestGetIngressClassParameters(t *testing.T) { Parameters: tc.paramRef, }, } + + require.NoError(t, fake.AddToScheme(scheme.Scheme)) client := ctrlfake.NewClientBuilder(). WithObjects( ingressClass, + icp, ). Build() - cacheStores, err := store.NewCacheStoresFromObjs(client, ingressClass, icp) // TODO(pmalek) - require.NoError(t, err) - err = cacheStores.Add(ingressClass) - require.NoError(t, err) - err = cacheStores.Add(icp) - require.NoError(t, err) - s := store.New(client, cacheStores, ingressClass.Name, logrus.New()) // TODO(pmalek) + s := store.New(client, ingressClass.Name, logrus.New()) icpSpec, err := getIngressClassParametersOrDefault(context.TODO(), s) assert.Truef(t, reflect.DeepEqual(*tc.parameterSpec, icpSpec), fmt.Sprintf("should get same ingress parameter spec: expected %+v, actual %+v", tc.parameterSpec, icpSpec), diff --git a/internal/dataplane/parser/ingressrules_test.go b/internal/dataplane/parser/ingressrules_test.go index e7c867c33d..965384f2ed 100644 --- a/internal/dataplane/parser/ingressrules_test.go +++ b/internal/dataplane/parser/ingressrules_test.go @@ -352,7 +352,7 @@ func TestGetK8sServicesForBackends(t *testing.T) { logger := logrus.New() logger.SetOutput(stdout) - services, annotations := getK8sServicesForBackends(context.TODO(), logger, storer, tt.namespace, tt.backends) //nolint:contextcheck + services, annotations := getK8sServicesForBackends(context.TODO(), logger, storer, tt.namespace, tt.backends) assert.Equal(t, tt.expectedServices, services) assert.Equal(t, tt.expectedAnnotations, annotations) for _, expectedLogEntry := range tt.expectedLogEntries { @@ -655,7 +655,7 @@ func TestPopulateServices(t *testing.T) { logger, _ := test.NewNullLogger() failuresCollector, err := failures.NewResourceFailuresCollector(logger) require.NoError(t, err) - servicesToBeSkipped := ingressRules.populateServices(context.TODO(), logrus.New(), fakeStore, failuresCollector) //nolint:contextcheck + servicesToBeSkipped := ingressRules.populateServices(context.TODO(), logrus.New(), fakeStore, failuresCollector) require.Equal(t, tc.serviceNamesToSkip, servicesToBeSkipped) require.Len(t, failuresCollector.PopResourceFailures(), len(servicesToBeSkipped), "expecting as many translation failures as services to skip") }) diff --git a/internal/dataplane/parser/parser.go b/internal/dataplane/parser/parser.go index 1a04f40e57..672ed5d9c7 100644 --- a/internal/dataplane/parser/parser.go +++ b/internal/dataplane/parser/parser.go @@ -85,14 +85,14 @@ func (p *Parser) Build(ctx context.Context) (*kongstate.KongState, []failures.Re ingressRules := mergeIngressRules( p.ingressRulesFromIngressV1beta1(ctx), p.ingressRulesFromIngressV1(ctx), - p.ingressRulesFromTCPIngressV1beta1(), - p.ingressRulesFromUDPIngressV1beta1(), - p.ingressRulesFromKnativeIngress(), - p.ingressRulesFromHTTPRoutes(), - p.ingressRulesFromUDPRoutes(), - p.ingressRulesFromTCPRoutes(), - p.ingressRulesFromTLSRoutes(), - p.ingressRulesFromGRPCRoutes(), + p.ingressRulesFromTCPIngressV1beta1(ctx), + p.ingressRulesFromUDPIngressV1beta1(ctx), + p.ingressRulesFromKnativeIngress(ctx), + p.ingressRulesFromHTTPRoutes(ctx), + p.ingressRulesFromUDPRoutes(ctx), + p.ingressRulesFromTCPRoutes(ctx), + p.ingressRulesFromTLSRoutes(ctx), + p.ingressRulesFromGRPCRoutes(ctx), ) // populate any Kubernetes Service objects relevant objects and get the @@ -113,7 +113,7 @@ func (p *Parser) Build(ctx context.Context) (*kongstate.KongState, []failures.Re result.Upstreams = p.getUpstreams(ctx, ingressRules.ServiceNameToServices) // merge KongIngress with Routes, Services and Upstream - result.FillOverrides(p.logger, p.storer) + result.FillOverrides(ctx, p.logger, p.storer) // generate consumers and credentials result.FillConsumersAndCredentials(ctx, p.logger, p.storer) @@ -303,7 +303,7 @@ func (p *Parser) getUpstreams(ctx context.Context, serviceMap map[string]kongsta } // get the new targets for this backend service - newTargets := getServiceEndpoints(ctx, p.logger, p.storer, k8sService, port) //nolint:contextcheck + newTargets := getServiceEndpoints(ctx, p.logger, p.storer, k8sService, port) if len(newTargets) == 0 { p.logger.WithField("service_name", *service.Name).Infof("no targets could be found for kubernetes service %s/%s", k8sService.Namespace, k8sService.Name) @@ -393,7 +393,7 @@ func (p *Parser) getGatewayCerts(ctx context.Context) []certWrapper { log := p.logger s := p.storer certs := []certWrapper{} - gateways, err := s.ListGateways() + gateways, err := s.ListGateways(ctx) if err != nil { log.WithError(err).Error("failed to list Gateways") return certs @@ -592,7 +592,7 @@ func getServiceEndpoints( // Check if the service is an upstream service through Ingress Class parameters. var isSvcUpstream bool - ingressClassParameters, err := getIngressClassParametersOrDefault(context.TODO(), s) + ingressClassParameters, err := getIngressClassParametersOrDefault(ctx, s) if err != nil { log.Debugf("error getting an IngressClassParameters: %v", err) } else { @@ -602,7 +602,7 @@ func getServiceEndpoints( // check all protocols for associated endpoints endpoints := []util.Endpoint{} for protocol := range protocols { - newEndpoints := getEndpoints(ctx, log, svc, servicePort, protocol, s.GetEndpointsForService, isSvcUpstream) //nolint:contextcheck + newEndpoints := getEndpoints(ctx, log, svc, servicePort, protocol, s.GetEndpointsForService, isSvcUpstream) if len(newEndpoints) > 0 { endpoints = append(endpoints, newEndpoints...) } @@ -624,7 +624,7 @@ func getIngressClassParametersOrDefault(ctx context.Context, s store.Storer) (co return configurationv1alpha1.IngressClassParametersSpec{}, err } - params, err := s.GetIngressClassParametersV1Alpha1(ingressClass) + params, err := s.GetIngressClassParametersV1Alpha1(ctx, ingressClass) if err != nil { return configurationv1alpha1.IngressClassParametersSpec{}, err } diff --git a/internal/dataplane/parser/parser_test.go b/internal/dataplane/parser/parser_test.go index da2419378b..c4a97b5586 100644 --- a/internal/dataplane/parser/parser_test.go +++ b/internal/dataplane/parser/parser_test.go @@ -730,12 +730,12 @@ func TestSecretConfigurationPlugin(t *testing.T) { require.Empty(t, translationFailures) assert.NotNil(state) for _, testcase := range references { - config, err := kongstate.SecretToConfiguration(context.TODO(), store, *testcase, "default") //nolint:contextcheck + config, err := kongstate.SecretToConfiguration(context.TODO(), store, *testcase, "default") assert.NotEmpty(config) assert.Nil(err) } for _, testcase := range badReferences { - config, err := kongstate.SecretToConfiguration(context.TODO(), store, *testcase, "default") //nolint:contextcheck + config, err := kongstate.SecretToConfiguration(context.TODO(), store, *testcase, "default") assert.Empty(config) assert.NotEmpty(err) } @@ -4317,7 +4317,7 @@ func TestGetEndpoints(t *testing.T) { for _, testCase := range tests { t.Run(testCase.name, func(t *testing.T) { - result := getEndpoints(context.TODO(), logrus.New(), testCase.svc, testCase.port, testCase.proto, testCase.fn, testCase.isServiceUpstream) //nolint:contextcheck + result := getEndpoints(context.TODO(), logrus.New(), testCase.svc, testCase.port, testCase.proto, testCase.fn, testCase.isServiceUpstream) if len(testCase.result) != len(result) { t.Errorf("expected %v Endpoints but got %v", testCase.result, len(result)) } diff --git a/internal/dataplane/parser/translate_grpcroute.go b/internal/dataplane/parser/translate_grpcroute.go index a9528ada34..e8ac00d40e 100644 --- a/internal/dataplane/parser/translate_grpcroute.go +++ b/internal/dataplane/parser/translate_grpcroute.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" "github.com/kong/go-kong/kong" @@ -18,10 +19,10 @@ import ( // ingressRulesFromGRPCRoutes processes a list of GRPCRoute objects and translates // then into Kong configuration objects. -func (p *Parser) ingressRulesFromGRPCRoutes() ingressRules { +func (p *Parser) ingressRulesFromGRPCRoutes(ctx context.Context) ingressRules { result := newIngressRules() - grpcRouteList, err := p.storer.ListGRPCRoutes() + grpcRouteList, err := p.storer.ListGRPCRoutes(ctx) if err != nil { p.logger.WithError(err).Error("failed to list GRPCRoutes") return result @@ -29,7 +30,7 @@ func (p *Parser) ingressRulesFromGRPCRoutes() ingressRules { var errs []error for _, grpcroute := range grpcRouteList { - if err := p.ingressRulesFromGRPCRoute(&result, grpcroute); err != nil { + if err := p.ingressRulesFromGRPCRoute(ctx, &result, grpcroute); err != nil { err = fmt.Errorf("GRPCRoute %s/%s can't be routed: %w", grpcroute.Namespace, grpcroute.Name, err) errs = append(errs, err) } else { @@ -48,7 +49,7 @@ func (p *Parser) ingressRulesFromGRPCRoutes() ingressRules { return result } -func (p *Parser) ingressRulesFromGRPCRoute(result *ingressRules, grpcroute *gatewayv1alpha2.GRPCRoute) error { +func (p *Parser) ingressRulesFromGRPCRoute(ctx context.Context, result *ingressRules, grpcroute *gatewayv1alpha2.GRPCRoute) error { // first we grab the spec and gather some metdata about the object spec := grpcroute.Spec @@ -63,7 +64,7 @@ func (p *Parser) ingressRulesFromGRPCRoute(result *ingressRules, grpcroute *gate routes := generateKongRoutesFromGRPCRouteRule(grpcroute, ruleNumber, rule) // create a service and attach the routes to it - service, err := generateKongServiceFromBackendRefWithRuleNumber(p.logger, p.storer, result, grpcroute, ruleNumber, "grpcs", grpcBackendRefsToBackendRefs(rule.BackendRefs)...) + service, err := generateKongServiceFromBackendRefWithRuleNumber(ctx, p.logger, p.storer, result, grpcroute, ruleNumber, "grpcs", grpcBackendRefsToBackendRefs(rule.BackendRefs)...) if err != nil { return err } diff --git a/internal/dataplane/parser/translate_httproute.go b/internal/dataplane/parser/translate_httproute.go index b7205cc420..7f1fc4d866 100644 --- a/internal/dataplane/parser/translate_httproute.go +++ b/internal/dataplane/parser/translate_httproute.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" pathlib "path" "strings" @@ -20,17 +21,17 @@ import ( // ingressRulesFromHTTPRoutes processes a list of HTTPRoute objects and translates // then into Kong configuration objects. -func (p *Parser) ingressRulesFromHTTPRoutes() ingressRules { +func (p *Parser) ingressRulesFromHTTPRoutes(ctx context.Context) ingressRules { result := newIngressRules() - httpRouteList, err := p.storer.ListHTTPRoutes() + httpRouteList, err := p.storer.ListHTTPRoutes(ctx) if err != nil { p.logger.WithError(err).Error("failed to list HTTPRoutes") return result } for _, httproute := range httpRouteList { - if err := p.ingressRulesFromHTTPRoute(&result, httproute); err != nil { + if err := p.ingressRulesFromHTTPRoute(ctx, &result, httproute); err != nil { p.registerTranslationFailure(fmt.Sprintf("HTTPRoute can't be routed: %s", err), httproute) } else { // at this point the object has been configured and can be @@ -42,16 +43,16 @@ func (p *Parser) ingressRulesFromHTTPRoutes() ingressRules { return result } -func (p *Parser) ingressRulesFromHTTPRoute(result *ingressRules, httproute *gatewayv1beta1.HTTPRoute) error { +func (p *Parser) ingressRulesFromHTTPRoute(ctx context.Context, result *ingressRules, httproute *gatewayv1beta1.HTTPRoute) error { if err := validateHTTPRoute(httproute); err != nil { return fmt.Errorf("validation failed : %w", err) } if p.featureEnabledCombinedServiceRoutes { - return p.ingressRulesFromHTTPRouteWithCombinedServiceRoutes(httproute, result) + return p.ingressRulesFromHTTPRouteWithCombinedServiceRoutes(ctx, httproute, result) } - return p.ingressRulesFromHTTPRouteLegacyFallback(httproute, result) + return p.ingressRulesFromHTTPRouteLegacyFallback(ctx, httproute, result) } func validateHTTPRoute(httproute *gatewayv1beta1.HTTPRoute) error { @@ -70,7 +71,7 @@ func validateHTTPRoute(httproute *gatewayv1beta1.HTTPRoute) error { // ingressRulesFromHTTPRouteWithCombinedServiceRoutes generates a set of proto-Kong routes (ingress rules) from an HTTPRoute. // If multiple rules in the HTTPRoute use the same Service, it combines them into a single Kong route. -func (p *Parser) ingressRulesFromHTTPRouteWithCombinedServiceRoutes(httproute *gatewayv1beta1.HTTPRoute, result *ingressRules) error { +func (p *Parser) ingressRulesFromHTTPRouteWithCombinedServiceRoutes(ctx context.Context, httproute *gatewayv1beta1.HTTPRoute, result *ingressRules) error { for _, kongServiceTranslation := range translators.TranslateHTTPRoute(httproute) { // HTTPRoute uses a wrapper HTTPBackendRef to add optional filters to its BackendRefs backendRefs := httpBackendRefsToBackendRefs(kongServiceTranslation.BackendRefs) @@ -78,7 +79,7 @@ func (p *Parser) ingressRulesFromHTTPRouteWithCombinedServiceRoutes(httproute *g serviceName := kongServiceTranslation.Name // create a service and attach the routes to it - service, err := generateKongServiceFromBackendRefWithName(p.logger, p.storer, result, serviceName, httproute, "http", backendRefs...) + service, err := generateKongServiceFromBackendRefWithName(ctx, p.logger, p.storer, result, serviceName, httproute, "http", backendRefs...) if err != nil { return err } @@ -103,7 +104,7 @@ func (p *Parser) ingressRulesFromHTTPRouteWithCombinedServiceRoutes(httproute *g // ingressRulesFromHTTPRouteLegacyFallback generates a set of proto-Kong routes (ingress rules) from an HTTPRoute. // It generates a separate route for each rule. // It is planned for deprecation in favor of ingressRulesFromHTTPRouteWithCombinedServiceRoutes. -func (p *Parser) ingressRulesFromHTTPRouteLegacyFallback(httproute *gatewayv1beta1.HTTPRoute, result *ingressRules) error { +func (p *Parser) ingressRulesFromHTTPRouteLegacyFallback(ctx context.Context, httproute *gatewayv1beta1.HTTPRoute, result *ingressRules) error { // each rule may represent a different set of backend services that will be accepting // traffic, so we make separate routes and Kong services for every present rule. for ruleNumber, rule := range httproute.Spec.Rules { @@ -117,7 +118,7 @@ func (p *Parser) ingressRulesFromHTTPRouteLegacyFallback(httproute *gatewayv1bet backendRefs := httpBackendRefsToBackendRefs(rule.BackendRefs) // create a service and attach the routes to it - service, err := generateKongServiceFromBackendRefWithRuleNumber(p.logger, p.storer, result, httproute, ruleNumber, "http", backendRefs...) + service, err := generateKongServiceFromBackendRefWithRuleNumber(ctx, p.logger, p.storer, result, httproute, ruleNumber, "http", backendRefs...) if err != nil { return err } diff --git a/internal/dataplane/parser/translate_httproute_test.go b/internal/dataplane/parser/translate_httproute_test.go index 4cf7b9859e..c35a668834 100644 --- a/internal/dataplane/parser/translate_httproute_test.go +++ b/internal/dataplane/parser/translate_httproute_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "testing" "github.com/kong/go-kong/kong" @@ -1248,7 +1249,7 @@ func TestIngressRulesFromHTTPRoutes(t *testing.T) { httproute.SetGroupVersionKind(httprouteGVK) // generate the ingress rules - err := p.ingressRulesFromHTTPRoute(&ingressRules, httproute) + err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) if err != nil { errs = append(errs, err) } @@ -1286,7 +1287,7 @@ func TestIngressRulesFromHTTPRoutesWithCombinedServiceRoutes(t *testing.T) { httproute.SetGroupVersionKind(httprouteGVK) // generate the ingress rules - err := p.ingressRulesFromHTTPRoute(&ingressRules, httproute) + err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) if err != nil { errs = append(errs, err) } @@ -1541,7 +1542,7 @@ func TestIngressRulesFromHTTPRoutes_RegexPrefix(t *testing.T) { httproute.SetGroupVersionKind(httprouteGVK) // generate the ingress rules - err := p.ingressRulesFromHTTPRoute(&ingressRules, httproute) + err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) if err != nil { errs = append(errs, err) } diff --git a/internal/dataplane/parser/translate_knative.go b/internal/dataplane/parser/translate_knative.go index 50805c44b4..4745957677 100644 --- a/internal/dataplane/parser/translate_knative.go +++ b/internal/dataplane/parser/translate_knative.go @@ -16,21 +16,21 @@ import ( "github.com/kong/kubernetes-ingress-controller/v2/internal/util" ) -func (p *Parser) ingressRulesFromKnativeIngress() ingressRules { +func (p *Parser) ingressRulesFromKnativeIngress(ctx context.Context) ingressRules { result := newIngressRules() // IngressClass is not actually part of the Knative spec, and we are getting networking.k8s.io IngressClasses here, // not a resource specific to Knative. However, the reason we're using it (enabling the 2.x regex heuristic) is // Kong-specific, so in absence of a proper Knative IngressClass to attach our IngressClassParams to, we may as // well use the stock Kubernetes resource. - icp, err := getIngressClassParametersOrDefault(context.TODO(), p.storer) + icp, err := getIngressClassParametersOrDefault(ctx, p.storer) if err != nil { if !errors.As(err, &store.ErrNotFound{}) { // anything else is unexpected p.logger.Errorf("could not find IngressClassParameters, using defaults: %s", err) } } - ingressList, err := p.storer.ListKnativeIngresses() + ingressList, err := p.storer.ListKnativeIngresses(ctx) if err != nil { p.logger.WithError(err).Error("failed to list Knative Ingresses") return result diff --git a/internal/dataplane/parser/translate_knative_test.go b/internal/dataplane/parser/translate_knative_test.go index aeeb41c823..86911fb816 100644 --- a/internal/dataplane/parser/translate_knative_test.go +++ b/internal/dataplane/parser/translate_knative_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "testing" "github.com/kong/go-kong/kong" @@ -222,7 +223,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress() + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(map[string]kongstate.Service{}, parsedInfo.ServiceNameToServices) assert.Equal(newSecretNameToSNIs(), parsedInfo.SecretNameToSNIs) }) @@ -235,7 +236,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress() + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(map[string]kongstate.Service{}, parsedInfo.ServiceNameToServices) assert.Equal(newSecretNameToSNIs(), parsedInfo.SecretNameToSNIs) }) @@ -248,7 +249,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress() + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["foo-ns.foo-svc.42"] assert.Equal(kong.Service{ @@ -297,7 +298,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress() + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(makeSecretToSNIs(map[string]testSNIs{ "foo-namespace/bar-secret": {hosts: []string{"bar.example.com", "bar1.example.com"}, parents: []client.Object{ingressList[3]}}, "foo-namespace/foo-secret": {hosts: []string{"foo.example.com", "foo1.example.com"}, parents: []client.Object{ingressList[3]}}, @@ -312,7 +313,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress() + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["foo-ns.foo-svc.42"] assert.Equal(kong.Service{ @@ -361,7 +362,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress() + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["foo-ns.foo-svc.42"] assert.Equal(translators.KongPathRegexPrefix+"/foo/\\d{3}", *svc.Routes[0].Route.Paths[0]) diff --git a/internal/dataplane/parser/translate_kong_l4.go b/internal/dataplane/parser/translate_kong_l4.go index 67b01e0690..52437d5a04 100644 --- a/internal/dataplane/parser/translate_kong_l4.go +++ b/internal/dataplane/parser/translate_kong_l4.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" "sort" "strconv" @@ -11,10 +12,10 @@ import ( "github.com/kong/kubernetes-ingress-controller/v2/internal/util" ) -func (p *Parser) ingressRulesFromTCPIngressV1beta1() ingressRules { +func (p *Parser) ingressRulesFromTCPIngressV1beta1(ctx context.Context) ingressRules { result := newIngressRules() - ingressList, err := p.storer.ListTCPIngresses() + ingressList, err := p.storer.ListTCPIngresses(ctx) if err != nil { p.logger.WithError(err).Error("failed to list TCPIngresses") return result @@ -87,10 +88,10 @@ func (p *Parser) ingressRulesFromTCPIngressV1beta1() ingressRules { return result } -func (p *Parser) ingressRulesFromUDPIngressV1beta1() ingressRules { +func (p *Parser) ingressRulesFromUDPIngressV1beta1(ctx context.Context) ingressRules { result := newIngressRules() - ingressList, err := p.storer.ListUDPIngresses() + ingressList, err := p.storer.ListUDPIngresses(ctx) if err != nil { p.logger.WithError(err).Errorf("failed to list UDPIngresses") return result diff --git a/internal/dataplane/parser/translate_kong_l4_test.go b/internal/dataplane/parser/translate_kong_l4_test.go index 8f9e327d8d..30df334828 100644 --- a/internal/dataplane/parser/translate_kong_l4_test.go +++ b/internal/dataplane/parser/translate_kong_l4_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "testing" "github.com/kong/go-kong/kong" @@ -106,7 +107,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1() + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(ingressRules{ ServiceNameToServices: make(map[string]kongstate.Service), ServiceNameToParent: make(map[string]client.Object), @@ -122,7 +123,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1() + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(ingressRules{ ServiceNameToServices: make(map[string]kongstate.Service), ServiceNameToParent: make(map[string]client.Object), @@ -138,7 +139,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1() + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["default.foo-svc.80"] assert.Equal("foo-svc.default.80.svc", *svc.Host) @@ -170,7 +171,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1() + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["default.foo-svc.80"] assert.Equal("foo-svc.default.80.svc", *svc.Host) @@ -203,7 +204,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1() + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("default/sooper-secret"))) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("default/sooper-secret2"))) }) diff --git a/internal/dataplane/parser/translate_secrets_test.go b/internal/dataplane/parser/translate_secrets_test.go index 91d5e2da3e..6593c128ef 100644 --- a/internal/dataplane/parser/translate_secrets_test.go +++ b/internal/dataplane/parser/translate_secrets_test.go @@ -54,7 +54,7 @@ func TestGetPluginsAssociatedWithCACertSecret(t *testing.T) { }) require.NoError(t, err) - gotPlugins := getPluginsAssociatedWithCACertSecret(context.TODO(), secretID, storer) //nolint:contextcheck + gotPlugins := getPluginsAssociatedWithCACertSecret(context.TODO(), secretID, storer) expectedPlugins := []client.Object{associatedPlugin, associatedClusterPlugin} require.ElementsMatch(t, expectedPlugins, gotPlugins, "expected plugins do not match actual ones") } diff --git a/internal/dataplane/parser/translate_tcproute.go b/internal/dataplane/parser/translate_tcproute.go index b3a12c7f51..8675f6b982 100644 --- a/internal/dataplane/parser/translate_tcproute.go +++ b/internal/dataplane/parser/translate_tcproute.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" @@ -12,10 +13,10 @@ import ( // ingressRulesFromTCPRoutes processes a list of TCPRoute objects and translates // then into Kong configuration objects. -func (p *Parser) ingressRulesFromTCPRoutes() ingressRules { +func (p *Parser) ingressRulesFromTCPRoutes(ctx context.Context) ingressRules { result := newIngressRules() - tcpRouteList, err := p.storer.ListTCPRoutes() + tcpRouteList, err := p.storer.ListTCPRoutes(ctx) if err != nil { p.logger.WithError(err).Error("failed to list TCPRoutes") return result @@ -23,7 +24,7 @@ func (p *Parser) ingressRulesFromTCPRoutes() ingressRules { var errs []error for _, tcproute := range tcpRouteList { - if err := p.ingressRulesFromTCPRoute(&result, tcproute); err != nil { + if err := p.ingressRulesFromTCPRoute(ctx, &result, tcproute); err != nil { err = fmt.Errorf("TCPRoute %s/%s can't be routed: %w", tcproute.Namespace, tcproute.Name, err) errs = append(errs, err) } else { @@ -42,7 +43,7 @@ func (p *Parser) ingressRulesFromTCPRoutes() ingressRules { return result } -func (p *Parser) ingressRulesFromTCPRoute(result *ingressRules, tcproute *gatewayv1alpha2.TCPRoute) error { +func (p *Parser) ingressRulesFromTCPRoute(ctx context.Context, result *ingressRules, tcproute *gatewayv1alpha2.TCPRoute) error { // first we grab the spec and gather some metdata about the object spec := tcproute.Spec @@ -71,7 +72,7 @@ func (p *Parser) ingressRulesFromTCPRoute(result *ingressRules, tcproute *gatewa } // create a service and attach the routes to it - service, err := generateKongServiceFromBackendRefWithRuleNumber(p.logger, p.storer, result, tcproute, ruleNumber, "tcp", rule.BackendRefs...) + service, err := generateKongServiceFromBackendRefWithRuleNumber(ctx, p.logger, p.storer, result, tcproute, ruleNumber, "tcp", rule.BackendRefs...) if err != nil { return err } diff --git a/internal/dataplane/parser/translate_tlsroute.go b/internal/dataplane/parser/translate_tlsroute.go index fa701bc583..8febd8ab06 100644 --- a/internal/dataplane/parser/translate_tlsroute.go +++ b/internal/dataplane/parser/translate_tlsroute.go @@ -1,6 +1,7 @@ package parser import ( + "context" "errors" "fmt" @@ -17,10 +18,10 @@ import ( // ingressRulesFromTLSRoutes processes a list of TLSRoute objects and translates // then into Kong configuration objects. -func (p *Parser) ingressRulesFromTLSRoutes() ingressRules { +func (p *Parser) ingressRulesFromTLSRoutes(ctx context.Context) ingressRules { result := newIngressRules() - tlsRouteList, err := p.storer.ListTLSRoutes() + tlsRouteList, err := p.storer.ListTLSRoutes(ctx) if err != nil { p.logger.WithError(err).Error("failed to list TLSRoutes") return result @@ -28,7 +29,7 @@ func (p *Parser) ingressRulesFromTLSRoutes() ingressRules { var errs []error for _, tlsroute := range tlsRouteList { - if err := p.ingressRulesFromTLSRoute(&result, tlsroute); err != nil { + if err := p.ingressRulesFromTLSRoute(ctx, &result, tlsroute); err != nil { err = fmt.Errorf("TLSRoute %s/%s can't be routed: %w", tlsroute.Namespace, tlsroute.Name, err) errs = append(errs, err) } else { @@ -47,7 +48,7 @@ func (p *Parser) ingressRulesFromTLSRoutes() ingressRules { return result } -func (p *Parser) ingressRulesFromTLSRoute(result *ingressRules, tlsroute *gatewayv1alpha2.TLSRoute) error { +func (p *Parser) ingressRulesFromTLSRoute(ctx context.Context, result *ingressRules, tlsroute *gatewayv1alpha2.TLSRoute) error { // first we grab the spec and gather some metdata about the object spec := tlsroute.Spec @@ -58,7 +59,7 @@ func (p *Parser) ingressRulesFromTLSRoute(result *ingressRules, tlsroute *gatewa return errRouteValidationNoRules } - tlsPassthrough, err := p.isTLSRoutePassthrough(tlsroute) + tlsPassthrough, err := p.isTLSRoutePassthrough(ctx, tlsroute) if err != nil { return err } @@ -79,7 +80,7 @@ func (p *Parser) ingressRulesFromTLSRoute(result *ingressRules, tlsroute *gatewa } // create a service and attach the routes to it - service, err := generateKongServiceFromBackendRefWithRuleNumber(p.logger, p.storer, result, tlsroute, ruleNumber, "tcp", rule.BackendRefs...) + service, err := generateKongServiceFromBackendRefWithRuleNumber(ctx, p.logger, p.storer, result, tlsroute, ruleNumber, "tcp", rule.BackendRefs...) if err != nil { return err } @@ -96,7 +97,7 @@ func (p *Parser) ingressRulesFromTLSRoute(result *ingressRules, tlsroute *gatewa // isTLSRoutePassthrough returns true if we need to configure TLS passthrough to kong // for the tlsroute object. // returns a non-nil error if we failed to get the supported gateway. -func (p *Parser) isTLSRoutePassthrough(tlsroute *gatewayv1alpha2.TLSRoute) (bool, error) { +func (p *Parser) isTLSRoutePassthrough(ctx context.Context, tlsroute *gatewayv1alpha2.TLSRoute) (bool, error) { // reconcile loop will push TLSRoute object with updated status when // gateway is ready and TLSRoute object becomes stable. // so we get the supported gateways from status.parents. @@ -116,7 +117,7 @@ func (p *Parser) isTLSRoutePassthrough(tlsroute *gatewayv1alpha2.TLSRoute) (bool gatewayNamespace = string(*parentRef.Namespace) } - gateway, err := p.storer.GetGateway(gatewayNamespace, string(parentRef.Name)) + gateway, err := p.storer.GetGateway(ctx, gatewayNamespace, string(parentRef.Name)) if err != nil { if errors.As(err, &store.ErrNotFound{}) { // log an error if the gateway expected to support the TLSRoute is not found in our cache. diff --git a/internal/dataplane/parser/translate_udproute.go b/internal/dataplane/parser/translate_udproute.go index 9216611012..be6b04b2bc 100644 --- a/internal/dataplane/parser/translate_udproute.go +++ b/internal/dataplane/parser/translate_udproute.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" @@ -12,10 +13,10 @@ import ( // ingressRulesFromUDPRoutes processes a list of UDPRoute objects and translates // then into Kong configuration objects. -func (p *Parser) ingressRulesFromUDPRoutes() ingressRules { +func (p *Parser) ingressRulesFromUDPRoutes(ctx context.Context) ingressRules { result := newIngressRules() - udpRouteList, err := p.storer.ListUDPRoutes() + udpRouteList, err := p.storer.ListUDPRoutes(ctx) if err != nil { p.logger.WithError(err).Errorf("failed to list UDPRoutes") return result @@ -23,7 +24,7 @@ func (p *Parser) ingressRulesFromUDPRoutes() ingressRules { var errs []error for _, udproute := range udpRouteList { - if err := p.ingressRulesFromUDPRoute(&result, udproute); err != nil { + if err := p.ingressRulesFromUDPRoute(ctx, &result, udproute); err != nil { err = fmt.Errorf("UDPRoute %s/%s can't be routed: %w", udproute.Namespace, udproute.Name, err) errs = append(errs, err) } else { @@ -42,7 +43,7 @@ func (p *Parser) ingressRulesFromUDPRoutes() ingressRules { return result } -func (p *Parser) ingressRulesFromUDPRoute(result *ingressRules, udproute *gatewayv1alpha2.UDPRoute) error { +func (p *Parser) ingressRulesFromUDPRoute(ctx context.Context, result *ingressRules, udproute *gatewayv1alpha2.UDPRoute) error { // first we grab the spec and gather some metdata about the object spec := udproute.Spec @@ -71,7 +72,7 @@ func (p *Parser) ingressRulesFromUDPRoute(result *ingressRules, udproute *gatewa } // create a service and attach the routes to it - service, err := generateKongServiceFromBackendRefWithRuleNumber(p.logger, p.storer, result, udproute, ruleNumber, "udp", rule.BackendRefs...) + service, err := generateKongServiceFromBackendRefWithRuleNumber(ctx, p.logger, p.storer, result, udproute, ruleNumber, "udp", rule.BackendRefs...) if err != nil { return err } diff --git a/internal/dataplane/parser/translate_utils.go b/internal/dataplane/parser/translate_utils.go index fe118fc256..c1b5262a3d 100644 --- a/internal/dataplane/parser/translate_utils.go +++ b/internal/dataplane/parser/translate_utils.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" "reflect" "strings" @@ -73,6 +74,7 @@ func getPermittedForReferenceGrantFrom( // generateKongServiceFromBackendRefWithName translates backendRefs into a Kong service for use with the // rules generated from a Gateway APIs route. The service name is provided by the caller. func generateKongServiceFromBackendRefWithName( + ctx context.Context, logger logrus.FieldLogger, storer store.Storer, rules *ingressRules, @@ -83,7 +85,7 @@ func generateKongServiceFromBackendRefWithName( ) (kongstate.Service, error) { objName := fmt.Sprintf("%s %s/%s", route.GetObjectKind().GroupVersionKind().String(), route.GetNamespace(), route.GetName()) - grants, err := storer.ListReferenceGrants() + grants, err := storer.ListReferenceGrants(ctx) if err != nil { return kongstate.Service{}, fmt.Errorf("could not retrieve ReferenceGrants for %s: %w", objName, err) } @@ -141,6 +143,7 @@ func generateKongServiceFromBackendRefWithName( // generateKongServiceFromBackendRefWithRuleNumber translates backendRefs for rule ruleNumber into a Kong service for use with the // rules generated from a Gateway APIs route. The service name is computed from route and ruleNumber by the function. func generateKongServiceFromBackendRefWithRuleNumber( + ctx context.Context, logger logrus.FieldLogger, storer store.Storer, rules *ingressRules, @@ -154,6 +157,7 @@ func generateKongServiceFromBackendRefWithRuleNumber( serviceName := fmt.Sprintf("%s.%d", getUniqueKongServiceNameForObject(route), ruleNumber) return generateKongServiceFromBackendRefWithName( + ctx, logger, storer, rules, diff --git a/internal/dataplane/parser/translate_utils_test.go b/internal/dataplane/parser/translate_utils_test.go index c332f8080f..edd342e4b2 100644 --- a/internal/dataplane/parser/translate_utils_test.go +++ b/internal/dataplane/parser/translate_utils_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "fmt" "testing" @@ -678,7 +679,7 @@ func TestGenerateKongServiceFromBackendRef(t *testing.T) { } for _, tt := range tests { t.Run(tt.msg, func(t *testing.T) { - result, err := generateKongServiceFromBackendRefWithRuleNumber(p.logger, p.storer, &rules, tt.route, ruleNumber, protocol, tt.refs...) + result, err := generateKongServiceFromBackendRefWithRuleNumber(context.TODO(), p.logger, p.storer, &rules, tt.route, ruleNumber, protocol, tt.refs...) assert.Equal(t, tt.result, result) if tt.wantErr { assert.NotNil(t, err) diff --git a/internal/store/fake_store.go b/internal/store/fake_store.go index 143a8f9049..f54906932c 100644 --- a/internal/store/fake_store.go +++ b/internal/store/fake_store.go @@ -239,23 +239,7 @@ func NewFakeStore( client := clientBuilder.Build() s := Store{ - client: client, - stores: CacheStores{ - HTTPRoute: httprouteStore, - UDPRoute: udprouteStore, - TCPRoute: tcprouteStore, - TLSRoute: tlsrouteStore, - GRPCRoute: grpcrouteStore, - ReferenceGrant: referencegrantStore, - Gateway: gatewayStore, - TCPIngress: tcpIngressStore, - UDPIngress: udpIngressStore, - - KongIngress: kongIngressStore, - IngressClassParametersV1alpha1: IngressClassParametersV1alpha1Store, - - KnativeIngress: knativeIngressStore, - }, + client: client, ingressClass: annotations.DefaultIngressClass, isValidIngressClass: annotations.IngressClassValidatorFuncFromObjectMeta(annotations.DefaultIngressClass), isValidIngressV1Class: annotations.IngressClassValidatorFuncFromV1Ingress(annotations.DefaultIngressClass), diff --git a/internal/store/fake_store_test.go b/internal/store/fake_store_test.go index 9e2554560d..1af60d7b58 100644 --- a/internal/store/fake_store_test.go +++ b/internal/store/fake_store_test.go @@ -371,7 +371,7 @@ func TestFakeStoreListTCPIngress(t *testing.T) { store, err := NewFakeStore(FakeObjects{TCPIngresses: ingresses}) require.Nil(err) require.NotNil(store) - ings, err := store.ListTCPIngresses() + ings, err := store.ListTCPIngresses(context.TODO()) assert.Nil(err) assert.Len(ings, 1) } @@ -444,7 +444,7 @@ func TestFakeStoreListKnativeIngress(t *testing.T) { store, err := NewFakeStore(FakeObjects{KnativeIngresses: ingresses}) require.Nil(err) require.NotNil(store) - ings, err := store.ListKnativeIngresses() + ings, err := store.ListKnativeIngresses(context.TODO()) assert.Len(ings, 1) assert.Nil(err) } @@ -464,11 +464,11 @@ func TestFakeStoreService(t *testing.T) { store, err := NewFakeStore(FakeObjects{Services: services}) require.Nil(err) require.NotNil(store) - service, err := store.GetService(context.TODO(), "default", "foo") //nolint:contextcheck + service, err := store.GetService(context.TODO(), "default", "foo") assert.NotNil(service) assert.Nil(err) - service, err = store.GetService(context.TODO(), "default", "does-not-exists") //nolint:contextcheck + service, err = store.GetService(context.TODO(), "default", "does-not-exists") assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(service) @@ -489,11 +489,11 @@ func TestFakeStoreEndpiont(t *testing.T) { store, err := NewFakeStore(FakeObjects{Endpoints: endpoints}) require.Nil(err) require.NotNil(store) - c, err := store.GetEndpointsForService(context.TODO(), "default", "foo") //nolint:contextcheck + c, err := store.GetEndpointsForService(context.TODO(), "default", "foo") assert.Nil(err) assert.NotNil(c) - c, err = store.GetEndpointsForService(context.TODO(), "default", "does-not-exist") //nolint:contextcheck + c, err = store.GetEndpointsForService(context.TODO(), "default", "does-not-exist") assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(c) @@ -517,12 +517,12 @@ func TestFakeStoreConsumer(t *testing.T) { store, err := NewFakeStore(FakeObjects{KongConsumers: consumers}) require.Nil(err) require.NotNil(store) - assert.Len(store.ListKongConsumers(context.TODO()), 1) //nolint:contextcheck - c, err := store.GetKongConsumer(context.TODO(), "default", "foo") //nolint:contextcheck + assert.Len(store.ListKongConsumers(context.TODO()), 1) + c, err := store.GetKongConsumer(context.TODO(), "default", "foo") assert.Nil(err) assert.NotNil(c) - c, err = store.GetKongConsumer(context.TODO(), "default", "does-not-exist") //nolint:contextcheck + c, err = store.GetKongConsumer(context.TODO(), "default", "does-not-exist") assert.Nil(c) assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) @@ -555,11 +555,11 @@ func TestFakeStorePlugins(t *testing.T) { store, err = NewFakeStore(FakeObjects{KongPlugins: plugins}) require.Nil(err) require.NotNil(store) - plugins, err = store.ListGlobalKongPlugins(context.TODO()) //nolint:contextcheck + plugins, err = store.ListGlobalKongPlugins(context.TODO()) assert.NoError(err) assert.Len(plugins, 0) - plugin, err := store.GetKongPlugin(context.TODO(), "default", "does-not-exist") //nolint:contextcheck + plugin, err := store.GetKongPlugin(context.TODO(), "default", "does-not-exist") assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(plugin) @@ -579,7 +579,7 @@ func TestFakeStoreClusterPlugins(t *testing.T) { store, err := NewFakeStore(FakeObjects{KongClusterPlugins: plugins}) require.Nil(err) require.NotNil(store) - plugins, err = store.ListGlobalKongClusterPlugins(context.TODO()) //nolint:contextcheck + plugins, err = store.ListGlobalKongClusterPlugins(context.TODO()) assert.NoError(err) assert.Len(plugins, 0) @@ -613,15 +613,15 @@ func TestFakeStoreClusterPlugins(t *testing.T) { store, err = NewFakeStore(FakeObjects{KongClusterPlugins: plugins}) require.Nil(err) require.NotNil(store) - plugins, err = store.ListGlobalKongClusterPlugins(context.TODO()) //nolint:contextcheck + plugins, err = store.ListGlobalKongClusterPlugins(context.TODO()) assert.NoError(err) assert.Len(plugins, 1) - plugin, err := store.GetKongClusterPlugin(context.TODO(), "foo") //nolint:contextcheck + plugin, err := store.GetKongClusterPlugin(context.TODO(), "foo") assert.NotNil(plugin) assert.Nil(err) - plugin, err = store.GetKongClusterPlugin(context.TODO(), "does-not-exist") //nolint:contextcheck + plugin, err = store.GetKongClusterPlugin(context.TODO(), "does-not-exist") assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) assert.Nil(plugin) @@ -642,11 +642,11 @@ func TestFakeStoreSecret(t *testing.T) { store, err := NewFakeStore(FakeObjects{Secrets: secrets}) require.Nil(err) require.NotNil(store) - secret, err := store.GetSecret(context.TODO(), "default", "foo") //nolint:contextcheck + secret, err := store.GetSecret(context.TODO(), "default", "foo") assert.Nil(err) assert.NotNil(secret) - secret, err = store.GetSecret(context.TODO(), "default", "does-not-exist") //nolint:contextcheck + secret, err = store.GetSecret(context.TODO(), "default", "does-not-exist") assert.Nil(secret) assert.NotNil(err) assert.True(errors.As(err, &ErrNotFound{})) @@ -667,11 +667,11 @@ func TestFakeKongIngress(t *testing.T) { store, err := NewFakeStore(FakeObjects{KongIngresses: kongIngresses}) require.Nil(err) require.NotNil(store) - kingress, err := store.GetKongIngress("default", "foo") + kingress, err := store.GetKongIngress(context.TODO(), "default", "foo") assert.Nil(err) assert.NotNil(kingress) - kingress, err = store.GetKongIngress("default", "does-not-exist") + kingress, err = store.GetKongIngress(context.TODO(), "default", "does-not-exist") assert.NotNil(err) assert.Nil(kingress) assert.True(errors.As(err, &ErrNotFound{})) @@ -692,7 +692,7 @@ func TestFakeStore_ListCACerts(t *testing.T) { store, err := NewFakeStore(FakeObjects{Secrets: secrets}) require.Nil(err) require.NotNil(store) - certs, err := store.ListCACerts(context.TODO()) //nolint:contextcheck + certs, err := store.ListCACerts(context.TODO()) assert.Nil(err) assert.Len(certs, 0) @@ -725,7 +725,7 @@ func TestFakeStore_ListCACerts(t *testing.T) { store, err = NewFakeStore(FakeObjects{Secrets: secrets}) require.Nil(err) require.NotNil(store) - certs, err = store.ListCACerts(context.TODO()) //nolint:contextcheck + certs, err = store.ListCACerts(context.TODO()) assert.Nil(err) assert.Len(certs, 2, "expect two secrets as CA certificates") } @@ -751,7 +751,7 @@ func TestFakeStoreHTTPRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{HTTPRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListHTTPRoutes() + routes, err := store.ListHTTPRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two HTTPRoutes") } @@ -777,7 +777,7 @@ func TestFakeStoreUDPRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{UDPRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListUDPRoutes() + routes, err := store.ListUDPRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two UDPRoutes") } @@ -803,7 +803,7 @@ func TestFakeStoreTCPRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{TCPRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListTCPRoutes() + routes, err := store.ListTCPRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two TCPRoutes") } @@ -829,7 +829,7 @@ func TestFakeStoreTLSRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{TLSRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListTLSRoutes() + routes, err := store.ListTLSRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two TLSRoutes") } @@ -855,7 +855,7 @@ func TestFakeStoreReferenceGrant(t *testing.T) { store, err := NewFakeStore(FakeObjects{ReferenceGrants: grants}) require.Nil(err) require.NotNil(store) - routes, err := store.ListReferenceGrants() + routes, err := store.ListReferenceGrants(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two ReferenceGrants") } @@ -881,7 +881,7 @@ func TestFakeStoreGateway(t *testing.T) { store, err := NewFakeStore(FakeObjects{Gateways: grants}) require.Nil(err) require.NotNil(store) - routes, err := store.ListGateways() + routes, err := store.ListGateways(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two Gateways") } diff --git a/internal/store/store.go b/internal/store/store.go index c4bdc0656b..3f826d60d3 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -27,7 +27,6 @@ import ( "github.com/samber/lo" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" netv1beta1 "k8s.io/api/networking/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -39,7 +38,6 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer/json" yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml" "k8s.io/apimachinery/pkg/selection" - "k8s.io/client-go/tools/cache" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" @@ -78,29 +76,29 @@ type Storer interface { GetSecret(ctx context.Context, namespace, name string) (*corev1.Secret, error) GetService(ctx context.Context, namespace, name string) (*corev1.Service, error) GetEndpointsForService(ctx context.Context, namespace, name string) (*corev1.Endpoints, error) - GetKongIngress(namespace, name string) (*kongv1.KongIngress, error) + GetKongIngress(ctx context.Context, namespace, name string) (*kongv1.KongIngress, error) GetKongPlugin(ctx context.Context, namespace, name string) (*kongv1.KongPlugin, error) GetKongClusterPlugin(ctx context.Context, name string) (*kongv1.KongClusterPlugin, error) GetKongConsumer(ctx context.Context, namespace, name string) (*kongv1.KongConsumer, error) GetIngressClassName() string GetIngressClassV1(ctx context.Context, name string) (*netv1.IngressClass, error) - GetIngressClassParametersV1Alpha1(ingressClass *netv1.IngressClass) (*kongv1alpha1.IngressClassParameters, error) - GetGateway(namespace string, name string) (*gatewayv1beta1.Gateway, error) + GetIngressClassParametersV1Alpha1(ctx context.Context, ingressClass *netv1.IngressClass) (*kongv1alpha1.IngressClassParameters, error) + GetGateway(ctx context.Context, namespace string, name string) (*gatewayv1beta1.Gateway, error) ListIngressesV1beta1(ctx context.Context) []*netv1beta1.Ingress ListIngressesV1(ctx context.Context) []*netv1.Ingress ListIngressClassesV1(ctx context.Context) []*netv1.IngressClass - ListIngressClassParametersV1Alpha1() []*kongv1alpha1.IngressClassParameters - ListHTTPRoutes() ([]*gatewayv1beta1.HTTPRoute, error) - ListUDPRoutes() ([]*gatewayv1alpha2.UDPRoute, error) - ListTCPRoutes() ([]*gatewayv1alpha2.TCPRoute, error) - ListTLSRoutes() ([]*gatewayv1alpha2.TLSRoute, error) - ListGRPCRoutes() ([]*gatewayv1alpha2.GRPCRoute, error) - ListReferenceGrants() ([]*gatewayv1beta1.ReferenceGrant, error) - ListGateways() ([]*gatewayv1beta1.Gateway, error) - ListTCPIngresses() ([]*kongv1beta1.TCPIngress, error) - ListUDPIngresses() ([]*kongv1beta1.UDPIngress, error) - ListKnativeIngresses() ([]*knative.Ingress, error) + ListIngressClassParametersV1Alpha1(ctx context.Context) []*kongv1alpha1.IngressClassParameters + ListHTTPRoutes(ctx context.Context) ([]*gatewayv1beta1.HTTPRoute, error) + ListUDPRoutes(ctx context.Context) ([]*gatewayv1alpha2.UDPRoute, error) + ListTCPRoutes(ctx context.Context) ([]*gatewayv1alpha2.TCPRoute, error) + ListTLSRoutes(ctx context.Context) ([]*gatewayv1alpha2.TLSRoute, error) + ListGRPCRoutes(ctx context.Context) ([]*gatewayv1alpha2.GRPCRoute, error) + ListReferenceGrants(ctx context.Context) ([]*gatewayv1beta1.ReferenceGrant, error) + ListGateways(ctx context.Context) ([]*gatewayv1beta1.Gateway, error) + ListTCPIngresses(ctx context.Context) ([]*kongv1beta1.TCPIngress, error) + ListUDPIngresses(ctx context.Context) ([]*kongv1beta1.UDPIngress, error) + ListKnativeIngresses(ctx context.Context) ([]*knative.Ingress, error) ListGlobalKongPlugins(ctx context.Context) ([]*kongv1.KongPlugin, error) ListGlobalKongClusterPlugins(ctx context.Context) ([]*kongv1.KongClusterPlugin, error) ListKongPlugins(ctx context.Context) []*kongv1.KongPlugin @@ -132,26 +130,6 @@ var _ Storer = Store{} // CacheStores stores cache.Store for all Kinds of k8s objects that // the Ingress Controller reads. type CacheStores struct { - // Core Kubernetes Stores - - // Gateway API Stores - HTTPRoute cache.Store - UDPRoute cache.Store - TCPRoute cache.Store - TLSRoute cache.Store - GRPCRoute cache.Store - ReferenceGrant cache.Store - Gateway cache.Store - - // Kong Stores - KongIngress cache.Store - TCPIngress cache.Store - UDPIngress cache.Store - IngressClassParametersV1alpha1 cache.Store - - // Knative Stores - KnativeIngress cache.Store - l *sync.RWMutex client client.Client @@ -164,20 +142,8 @@ func NewCacheStores(client client.Client) CacheStores { // Core Kubernetes Stores // Gateway API Stores - HTTPRoute: cache.NewStore(keyFunc), - UDPRoute: cache.NewStore(keyFunc), - TCPRoute: cache.NewStore(keyFunc), - TLSRoute: cache.NewStore(keyFunc), - GRPCRoute: cache.NewStore(keyFunc), - ReferenceGrant: cache.NewStore(keyFunc), - Gateway: cache.NewStore(keyFunc), // Kong Stores - KongIngress: cache.NewStore(keyFunc), - TCPIngress: cache.NewStore(keyFunc), - UDPIngress: cache.NewStore(keyFunc), - IngressClassParametersV1alpha1: cache.NewStore(keyFunc), // Knative Stores - KnativeIngress: cache.NewStore(keyFunc), l: &sync.RWMutex{}, } @@ -218,160 +184,18 @@ func NewCacheStoresFromObjs(client client.Client, objs ...runtime.Object) (Cache return c, err } - if err := c.Add(typedObj); err != nil { - return c, err - } + // TODO(pmalek) + // if err := c.Add(typedObj); err != nil { + // return c, err + // } } return c, nil } -// Get checks whether or not there's already some version of the provided object present in the cache. -func (c CacheStores) Get(obj runtime.Object) (item interface{}, exists bool, err error) { - c.l.RLock() - defer c.l.RUnlock() - - switch obj := obj.(type) { - // ---------------------------------------------------------------------------- - // Kubernetes Core API Support - // ---------------------------------------------------------------------------- - // ---------------------------------------------------------------------------- - // Kubernetes Gateway API Support - // ---------------------------------------------------------------------------- - case *gatewayv1beta1.HTTPRoute: - return c.HTTPRoute.Get(obj) - case *gatewayv1alpha2.UDPRoute: - return c.UDPRoute.Get(obj) - case *gatewayv1alpha2.TCPRoute: - return c.TCPRoute.Get(obj) - case *gatewayv1alpha2.TLSRoute: - return c.TLSRoute.Get(obj) - case *gatewayv1alpha2.GRPCRoute: - return c.GRPCRoute.Get(obj) - case *gatewayv1beta1.ReferenceGrant: - return c.ReferenceGrant.Get(obj) - case *gatewayv1beta1.Gateway: - return c.Gateway.Get(obj) - // ---------------------------------------------------------------------------- - // Kong API Support - // ---------------------------------------------------------------------------- - case *kongv1.KongIngress: - return c.KongIngress.Get(obj) - case *kongv1beta1.TCPIngress: - return c.TCPIngress.Get(obj) - case *kongv1beta1.UDPIngress: - return c.UDPIngress.Get(obj) - case *kongv1alpha1.IngressClassParameters: - return c.IngressClassParametersV1alpha1.Get(obj) - // ---------------------------------------------------------------------------- - // 3rd Party API Support - // ---------------------------------------------------------------------------- - case *knative.Ingress: - return c.KnativeIngress.Get(obj) - } - return nil, false, fmt.Errorf("%T is not a supported cache object type", obj) -} - -// Add stores a provided runtime.Object into the CacheStore if it's of a supported type. -// The CacheStore must be initialized (see NewCacheStores()) or this will panic. -func (c CacheStores) Add(obj runtime.Object) error { - c.l.Lock() - defer c.l.Unlock() - - switch obj := obj.(type) { - // ---------------------------------------------------------------------------- - // Kubernetes Core API Support - // ---------------------------------------------------------------------------- - // ---------------------------------------------------------------------------- - // Kubernetes Gateway API Support - // ---------------------------------------------------------------------------- - case *gatewayv1beta1.HTTPRoute: - return c.HTTPRoute.Add(obj) - case *gatewayv1alpha2.UDPRoute: - return c.UDPRoute.Add(obj) - case *gatewayv1alpha2.TCPRoute: - return c.TCPRoute.Add(obj) - case *gatewayv1alpha2.TLSRoute: - return c.TLSRoute.Add(obj) - case *gatewayv1alpha2.GRPCRoute: - return c.GRPCRoute.Add(obj) - case *gatewayv1beta1.ReferenceGrant: - return c.ReferenceGrant.Add(obj) - case *gatewayv1beta1.Gateway: - return c.Gateway.Add(obj) - // ---------------------------------------------------------------------------- - // Kong API Support - // ---------------------------------------------------------------------------- - case *kongv1.KongIngress: - return c.KongIngress.Add(obj) - case *kongv1beta1.TCPIngress: - return c.TCPIngress.Add(obj) - case *kongv1beta1.UDPIngress: - return c.UDPIngress.Add(obj) - case *kongv1alpha1.IngressClassParameters: - return c.IngressClassParametersV1alpha1.Add(obj) - // ---------------------------------------------------------------------------- - // 3rd Party API Support - // ---------------------------------------------------------------------------- - case *knative.Ingress: - return c.KnativeIngress.Add(obj) - default: - return fmt.Errorf("cannot add unsupported kind %q to the store", obj.GetObjectKind().GroupVersionKind()) - } -} - -// Delete removes a provided runtime.Object from the CacheStore if it's of a supported type. -// The CacheStore must be initialized (see NewCacheStores()) or this will panic. -func (c CacheStores) Delete(obj runtime.Object) error { - c.l.Lock() - defer c.l.Unlock() - - switch obj := obj.(type) { - // ---------------------------------------------------------------------------- - // Kubernetes Core API Support - // ---------------------------------------------------------------------------- - // ---------------------------------------------------------------------------- - // Kubernetes Gateway API Support - // ---------------------------------------------------------------------------- - case *gatewayv1beta1.HTTPRoute: - return c.HTTPRoute.Delete(obj) - case *gatewayv1alpha2.UDPRoute: - return c.UDPRoute.Delete(obj) - case *gatewayv1alpha2.TCPRoute: - return c.TCPRoute.Delete(obj) - case *gatewayv1alpha2.TLSRoute: - return c.TLSRoute.Delete(obj) - case *gatewayv1alpha2.GRPCRoute: - return c.GRPCRoute.Delete(obj) - case *gatewayv1beta1.ReferenceGrant: - return c.ReferenceGrant.Delete(obj) - case *gatewayv1beta1.Gateway: - return c.Gateway.Delete(obj) - // ---------------------------------------------------------------------------- - // Kong API Support - // ---------------------------------------------------------------------------- - case *kongv1.KongIngress: - return c.KongIngress.Delete(obj) - case *kongv1beta1.TCPIngress: - return c.TCPIngress.Delete(obj) - case *kongv1beta1.UDPIngress: - return c.UDPIngress.Delete(obj) - case *kongv1alpha1.IngressClassParameters: - return c.IngressClassParametersV1alpha1.Delete(obj) - // ---------------------------------------------------------------------------- - // 3rd Party API Support - // ---------------------------------------------------------------------------- - case *knative.Ingress: - return c.KnativeIngress.Delete(obj) - default: - return fmt.Errorf("cannot delete unsupported kind %q from the store", obj.GetObjectKind().GroupVersionKind()) - } -} - // New creates a new object store to be used in the ingress controller. -func New(client client.Client, cs CacheStores, ingressClass string, logger logrus.FieldLogger) Storer { +func New(client client.Client, ingressClass string, logger logrus.FieldLogger) Storer { return Store{ client: client, - stores: cs, ingressClass: ingressClass, ingressClassMatching: annotations.ExactClassMatch, isValidIngressClass: annotations.IngressClassValidatorFuncFromObjectMeta(ingressClass), @@ -389,11 +213,11 @@ func (s Store) GetSecret(ctx context.Context, namespace, name string) (*corev1.S var secret corev1.Secret err := s.client.Get(ctx, key, &secret) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("Secret %v not found", name)} + } return nil, err } - if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("Secret %v not found", name)} - } return &secret, nil } @@ -403,14 +227,14 @@ func (s Store) GetService(ctx context.Context, namespace, name string) (*corev1. Namespace: namespace, Name: name, } - var svc v1.Service + var svc corev1.Service err := s.client.Get(ctx, key, &svc) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("Service %v not found", name)} + } return nil, err } - if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("Service %v not found", name)} - } return &svc, nil } @@ -446,8 +270,10 @@ func (s Store) ListIngressesV1(ctx context.Context) []*netv1.Ingress { } sort.SliceStable(ingresses, func(i, j int) bool { - return strings.Compare(fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), - fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name)) < 0 + return strings.Compare( + fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), + fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name), + ) < 0 }) return ingresses @@ -476,25 +302,25 @@ func (s Store) ListIngressClassesV1(ctx context.Context) []*netv1.IngressClass { } // ListIngressClassParametersV1Alpha1 returns the list of IngressClassParameters in the Ingress v1alpha1 store. -func (s Store) ListIngressClassParametersV1Alpha1() []*kongv1alpha1.IngressClassParameters { - var classParams []*kongv1alpha1.IngressClassParameters - for _, item := range s.stores.IngressClassParametersV1alpha1.List() { - classParam, ok := item.(*kongv1alpha1.IngressClassParameters) - if !ok { - s.logger.Warnf("listIngressClassParametersV1alpha1: dropping object of unexpected type: %#v", item) - continue - } - classParams = append(classParams, classParam) +func (s Store) ListIngressClassParametersV1Alpha1(ctx context.Context) []*kongv1alpha1.IngressClassParameters { + var icpList kongv1alpha1.IngressClassParametersList + if err := s.client.List(ctx, &icpList); err != nil { + return nil } - sort.SliceStable(classParams, func(i, j int) bool { + icps := lo.Map(icpList.Items, + func(p kongv1alpha1.IngressClassParameters, _ int) *kongv1alpha1.IngressClassParameters { + return &p + }) + + sort.SliceStable(icps, func(i, j int) bool { return strings.Compare( - fmt.Sprintf("%s/%s", classParams[i].Namespace, classParams[i].Name), - fmt.Sprintf("%s/%s", classParams[j].Namespace, classParams[j].Name), + fmt.Sprintf("%s/%s", icps[i].Namespace, icps[i].Name), + fmt.Sprintf("%s/%s", icps[j].Namespace, icps[j].Name), ) < 0 }) - return classParams + return icps } // ListIngressesV1beta1 returns the list of Ingresses in the Ingress v1beta1 store. @@ -512,196 +338,252 @@ func (s Store) ListIngressesV1beta1(ctx context.Context) []*netv1beta1.Ingress { } ingresses = append(ingresses, &ing) } + sort.SliceStable(ingresses, func(i, j int) bool { - return strings.Compare(fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), - fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name)) < 0 + return strings.Compare( + fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), + fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name), + ) < 0 }) return ingresses } // ListHTTPRoutes returns the list of HTTPRoutes in the HTTPRoute cache store. -func (s Store) ListHTTPRoutes() ([]*gatewayv1beta1.HTTPRoute, error) { - var httproutes []*gatewayv1beta1.HTTPRoute - if err := cache.ListAll(s.stores.HTTPRoute, labels.NewSelector(), - func(ob interface{}) { - httproute, ok := ob.(*gatewayv1beta1.HTTPRoute) - if ok { - httproutes = append(httproutes, httproute) - } - }, - ); err != nil { +func (s Store) ListHTTPRoutes(ctx context.Context) ([]*gatewayv1beta1.HTTPRoute, error) { + var list gatewayv1beta1.HTTPRouteList + if err := s.client.List(ctx, &list); err != nil { return nil, err } - return httproutes, nil + + items := lo.Map(list.Items, + func(p gatewayv1beta1.HTTPRoute, _ int) *gatewayv1beta1.HTTPRoute { + return &p + }) + + sort.SliceStable(items, func(i, j int) bool { + return strings.Compare( + fmt.Sprintf("%s/%s", items[i].Namespace, items[i].Name), + fmt.Sprintf("%s/%s", items[j].Namespace, items[j].Name), + ) < 0 + }) + + return items, nil } // ListUDPRoutes returns the list of UDPRoutes in the UDPRoute cache store. -func (s Store) ListUDPRoutes() ([]*gatewayv1alpha2.UDPRoute, error) { - var udproutes []*gatewayv1alpha2.UDPRoute - if err := cache.ListAll(s.stores.UDPRoute, labels.NewSelector(), - func(ob interface{}) { - udproute, ok := ob.(*gatewayv1alpha2.UDPRoute) - if ok { - udproutes = append(udproutes, udproute) - } - }, - ); err != nil { +func (s Store) ListUDPRoutes(ctx context.Context) ([]*gatewayv1alpha2.UDPRoute, error) { + var list gatewayv1alpha2.UDPRouteList + if err := s.client.List(ctx, &list); err != nil { return nil, err } - return udproutes, nil + + items := lo.Map(list.Items, + func(p gatewayv1alpha2.UDPRoute, _ int) *gatewayv1alpha2.UDPRoute { + return &p + }) + + sort.SliceStable(items, func(i, j int) bool { + return strings.Compare( + fmt.Sprintf("%s/%s", items[i].Namespace, items[i].Name), + fmt.Sprintf("%s/%s", items[j].Namespace, items[j].Name), + ) < 0 + }) + + return items, nil } // ListTCPRoutes returns the list of TCPRoutes in the TCPRoute cache store. -func (s Store) ListTCPRoutes() ([]*gatewayv1alpha2.TCPRoute, error) { - var tcproutes []*gatewayv1alpha2.TCPRoute - if err := cache.ListAll(s.stores.TCPRoute, labels.NewSelector(), - func(ob interface{}) { - tcproute, ok := ob.(*gatewayv1alpha2.TCPRoute) - if ok { - tcproutes = append(tcproutes, tcproute) - } - }, - ); err != nil { +func (s Store) ListTCPRoutes(ctx context.Context) ([]*gatewayv1alpha2.TCPRoute, error) { + var list gatewayv1alpha2.TCPRouteList + if err := s.client.List(ctx, &list); err != nil { return nil, err } - return tcproutes, nil + + items := lo.Map(list.Items, + func(p gatewayv1alpha2.TCPRoute, _ int) *gatewayv1alpha2.TCPRoute { + return &p + }) + + sort.SliceStable(items, func(i, j int) bool { + return strings.Compare( + fmt.Sprintf("%s/%s", items[i].Namespace, items[i].Name), + fmt.Sprintf("%s/%s", items[j].Namespace, items[j].Name), + ) < 0 + }) + + return items, nil } // ListTLSRoutes returns the list of TLSRoutes in the TLSRoute cache store. -func (s Store) ListTLSRoutes() ([]*gatewayv1alpha2.TLSRoute, error) { - var tlsroutes []*gatewayv1alpha2.TLSRoute - if err := cache.ListAll(s.stores.TLSRoute, labels.NewSelector(), - func(ob interface{}) { - tlsroute, ok := ob.(*gatewayv1alpha2.TLSRoute) - if ok { - tlsroutes = append(tlsroutes, tlsroute) - } - }, - ); err != nil { +func (s Store) ListTLSRoutes(ctx context.Context) ([]*gatewayv1alpha2.TLSRoute, error) { + var list gatewayv1alpha2.TLSRouteList + if err := s.client.List(ctx, &list); err != nil { return nil, err } - return tlsroutes, nil + + items := lo.Map(list.Items, + func(p gatewayv1alpha2.TLSRoute, _ int) *gatewayv1alpha2.TLSRoute { + return &p + }) + + sort.SliceStable(items, func(i, j int) bool { + return strings.Compare( + fmt.Sprintf("%s/%s", items[i].Namespace, items[i].Name), + fmt.Sprintf("%s/%s", items[j].Namespace, items[j].Name), + ) < 0 + }) + + return items, nil } // ListGRPCRoutes returns the list of GRPCRoutes in the GRPCRoute cache store. -func (s Store) ListGRPCRoutes() ([]*gatewayv1alpha2.GRPCRoute, error) { - var grpcroutes []*gatewayv1alpha2.GRPCRoute - if err := cache.ListAll(s.stores.GRPCRoute, labels.NewSelector(), - func(ob interface{}) { - tlsroute, ok := ob.(*gatewayv1alpha2.GRPCRoute) - if ok { - grpcroutes = append(grpcroutes, tlsroute) - } - }, - ); err != nil { +func (s Store) ListGRPCRoutes(ctx context.Context) ([]*gatewayv1alpha2.GRPCRoute, error) { + var list gatewayv1alpha2.GRPCRouteList + if err := s.client.List(ctx, &list); err != nil { return nil, err } - return grpcroutes, nil + + items := lo.Map(list.Items, + func(p gatewayv1alpha2.GRPCRoute, _ int) *gatewayv1alpha2.GRPCRoute { + return &p + }) + + sort.SliceStable(items, func(i, j int) bool { + return strings.Compare( + fmt.Sprintf("%s/%s", items[i].Namespace, items[i].Name), + fmt.Sprintf("%s/%s", items[j].Namespace, items[j].Name), + ) < 0 + }) + + return items, nil } // ListReferenceGrants returns the list of ReferenceGrants in the ReferenceGrant cache store. -func (s Store) ListReferenceGrants() ([]*gatewayv1beta1.ReferenceGrant, error) { - var grants []*gatewayv1beta1.ReferenceGrant - if err := cache.ListAll(s.stores.ReferenceGrant, labels.NewSelector(), - func(ob interface{}) { - grant, ok := ob.(*gatewayv1beta1.ReferenceGrant) - if ok { - grants = append(grants, grant) - } - }, - ); err != nil { +func (s Store) ListReferenceGrants(ctx context.Context) ([]*gatewayv1beta1.ReferenceGrant, error) { + var list gatewayv1beta1.ReferenceGrantList + if err := s.client.List(ctx, &list); err != nil { return nil, err } - return grants, nil + + items := lo.Map(list.Items, + func(p gatewayv1beta1.ReferenceGrant, _ int) *gatewayv1beta1.ReferenceGrant { + return &p + }) + + sort.SliceStable(items, func(i, j int) bool { + return strings.Compare( + fmt.Sprintf("%s/%s", items[i].Namespace, items[i].Name), + fmt.Sprintf("%s/%s", items[j].Namespace, items[j].Name), + ) < 0 + }) + + return items, nil } // ListGateways returns the list of Gateways in the Gateway cache store. -func (s Store) ListGateways() ([]*gatewayv1beta1.Gateway, error) { - var gateways []*gatewayv1beta1.Gateway - if err := cache.ListAll(s.stores.Gateway, labels.NewSelector(), - func(ob interface{}) { - gw, ok := ob.(*gatewayv1beta1.Gateway) - if ok { - gateways = append(gateways, gw) - } - }, - ); err != nil { +func (s Store) ListGateways(ctx context.Context) ([]*gatewayv1beta1.Gateway, error) { + var list gatewayv1beta1.GatewayList + if err := s.client.List(ctx, &list); err != nil { return nil, err } - return gateways, nil + + items := lo.Map(list.Items, + func(p gatewayv1beta1.Gateway, _ int) *gatewayv1beta1.Gateway { + return &p + }) + + sort.SliceStable(items, func(i, j int) bool { + return strings.Compare( + fmt.Sprintf("%s/%s", items[i].Namespace, items[i].Name), + fmt.Sprintf("%s/%s", items[j].Namespace, items[j].Name), + ) < 0 + }) + + return items, nil } // ListTCPIngresses returns the list of TCP Ingresses from // configuration.konghq.com group. -func (s Store) ListTCPIngresses() ([]*kongv1beta1.TCPIngress, error) { - var ingresses []*kongv1beta1.TCPIngress - err := cache.ListAll(s.stores.TCPIngress, labels.NewSelector(), - func(ob interface{}) { - ing, ok := ob.(*kongv1beta1.TCPIngress) - if ok && s.isValidIngressClass(&ing.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { - ingresses = append(ingresses, ing) - } - }) - if err != nil { +func (s Store) ListTCPIngresses(ctx context.Context) ([]*kongv1beta1.TCPIngress, error) { + var ( + ingresses []*kongv1beta1.TCPIngress + ingressList kongv1beta1.TCPIngressList + ) + if err := s.client.List(ctx, &ingressList); err != nil { return nil, err } + + handlingClass := s.getIngressClassHandling(ctx) + for i := range ingressList.Items { + ingress := ingressList.Items[i] + if s.isValidIngressClass(&ingress.ObjectMeta, annotations.IngressClassKey, handlingClass) { + ingresses = append(ingresses, &ingress) + } + } + sort.SliceStable(ingresses, func(i, j int) bool { - return strings.Compare(fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), - fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name)) < 0 + return strings.Compare( + fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), + fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name), + ) < 0 }) return ingresses, nil } // ListUDPIngresses returns the list of UDP Ingresses. -func (s Store) ListUDPIngresses() ([]*kongv1beta1.UDPIngress, error) { - ingresses := []*kongv1beta1.UDPIngress{} - if s.stores.UDPIngress == nil { +func (s Store) ListUDPIngresses(ctx context.Context) ([]*kongv1beta1.UDPIngress, error) { + var ( + ingresses []*kongv1beta1.UDPIngress + ingressList kongv1beta1.UDPIngressList + ) + if err := s.client.List(ctx, &ingressList); err != nil { // older versions of the KIC do not support UDPIngress so short circuit to maintain support with them - return ingresses, nil + return nil, err + } + + handlingClass := s.getIngressClassHandling(ctx) + for i := range ingressList.Items { + ingress := ingressList.Items[i] + if s.isValidIngressClass(&ingress.ObjectMeta, annotations.IngressClassKey, handlingClass) { + ingresses = append(ingresses, &ingress) + } } - err := cache.ListAll(s.stores.UDPIngress, labels.NewSelector(), - func(ob interface{}) { - ing, ok := ob.(*kongv1beta1.UDPIngress) - if ok && s.isValidIngressClass(&ing.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { - ingresses = append(ingresses, ing) - } - }) sort.SliceStable(ingresses, func(i, j int) bool { - return strings.Compare(fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), - fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name)) < 0 + return strings.Compare( + fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), + fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name), + ) < 0 }) - return ingresses, err + return ingresses, nil } // ListKnativeIngresses returns the list of Knative Ingresses from // ingresses.networking.internal.knative.dev group. -func (s Store) ListKnativeIngresses() ([]*knative.Ingress, error) { - var ingresses []*knative.Ingress - if s.stores.KnativeIngress == nil { - return ingresses, nil +func (s Store) ListKnativeIngresses(ctx context.Context) ([]*knative.Ingress, error) { + var ( + ingresses []*knative.Ingress + ingressList knative.IngressList + ) + if err := s.client.List(ctx, &ingressList); err != nil { + return nil, err } - err := cache.ListAll( - s.stores.KnativeIngress, - labels.NewSelector(), - func(ob interface{}) { - ing, ok := ob.(*knative.Ingress) - if ok { - handlingClass := s.getIngressClassHandling() - if s.isValidIngressClass(&ing.ObjectMeta, annotations.KnativeIngressClassKey, handlingClass) || - s.isValidIngressClass(&ing.ObjectMeta, annotations.KnativeIngressClassDeprecatedKey, handlingClass) { - ingresses = append(ingresses, ing) - } - } - }) - if err != nil { - return nil, err + handlingClass := s.getIngressClassHandling(ctx) + for i := range ingressList.Items { + ingress := ingressList.Items[i] + if s.isValidIngressClass(&ingress.ObjectMeta, annotations.KnativeIngressClassKey, handlingClass) || + s.isValidIngressClass(&ingress.ObjectMeta, annotations.KnativeIngressClassDeprecatedKey, handlingClass) { + ingresses = append(ingresses, &ingress) + } + } sort.SliceStable(ingresses, func(i, j int) bool { - return strings.Compare(fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), - fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name)) < 0 + return strings.Compare( + fmt.Sprintf("%s/%s", ingresses[i].Namespace, ingresses[i].Name), + fmt.Sprintf("%s/%s", ingresses[j].Namespace, ingresses[j].Name), + ) < 0 }) return ingresses, nil } @@ -718,11 +600,11 @@ func (s Store) GetEndpointsForService(ctx context.Context, namespace, name strin err := s.client.Get(ctx, key, &endpoints) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("Endpoints for service %v not found", key)} + } return nil, err } - if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("Endpoints for service %v not found", key)} - } return &endpoints, nil } @@ -738,11 +620,11 @@ func (s Store) GetKongPlugin(ctx context.Context, namespace, name string) (*kong err := s.client.Get(ctx, key, &plugin) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("KongPlugin %v not found", key)} + } return nil, err } - if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("KongPlugin %v not found", key)} - } return &plugin, nil } @@ -757,25 +639,32 @@ func (s Store) GetKongClusterPlugin(ctx context.Context, name string) (*kongv1.K err := s.client.Get(ctx, key, &plugin) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("KongClusterPlugin %v not found", key)} + } return nil, err } - if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("KongClusterPlugin %v not found", key)} - } return &plugin, nil } // GetKongIngress returns the 'name' KongIngress resource in namespace. -func (s Store) GetKongIngress(namespace, name string) (*kongv1.KongIngress, error) { - key := fmt.Sprintf("%v/%v", namespace, name) - p, exists, err := s.stores.KongIngress.GetByKey(key) +func (s Store) GetKongIngress(ctx context.Context, namespace, name string) (*kongv1.KongIngress, error) { + var ( + ingress kongv1.KongIngress + key = client.ObjectKey{ + Namespace: namespace, + Name: name, + } + ) + + err := s.client.Get(ctx, key, &ingress) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("KongIngress %v not found", key)} + } return nil, err } - if !exists { - return nil, ErrNotFound{fmt.Sprintf("KongIngress %v not found", name)} - } - return p.(*kongv1.KongIngress), nil + return &ingress, nil } // GetKongConsumer returns the 'name' KongConsumer resource in namespace. @@ -790,11 +679,11 @@ func (s Store) GetKongConsumer(ctx context.Context, namespace, name string) (*ko err := s.client.Get(ctx, key, &consumer) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("KongConsumer %v not found", key)} + } return nil, err } - if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("KongConsumer %v not found", key)} - } return &consumer, nil } @@ -813,17 +702,17 @@ func (s Store) GetIngressClassV1(ctx context.Context, name string) (*netv1.Ingre err := s.client.Get(ctx, key, &ingressClass) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("IngressClass %v not found", name)} + } return nil, err } - if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("IngressClass %v not found", name)} - } return &ingressClass, nil } // GetIngressClassParametersV1Alpha1 returns IngressClassParameters for provided // IngressClass. -func (s Store) GetIngressClassParametersV1Alpha1(ingressClass *netv1.IngressClass) (*kongv1alpha1.IngressClassParameters, error) { +func (s Store) GetIngressClassParametersV1Alpha1(ctx context.Context, ingressClass *netv1.IngressClass) (*kongv1alpha1.IngressClassParameters, error) { if ingressClass == nil { return nil, fmt.Errorf("provided IngressClass is nil") } @@ -853,28 +742,39 @@ func (s Store) GetIngressClassParametersV1Alpha1(ingressClass *netv1.IngressClas return nil, fmt.Errorf("IngressClass %s should reference namespaced parameters", ingressClass.Name) } - key := fmt.Sprintf("%v/%v", *ingressClass.Spec.Parameters.Namespace, ingressClass.Spec.Parameters.Name) - params, exists, err := s.stores.IngressClassParametersV1alpha1.GetByKey(key) + key := client.ObjectKey{ + Namespace: *ingressClass.Spec.Parameters.Namespace, + Name: ingressClass.Spec.Parameters.Name, + } + var icp kongv1alpha1.IngressClassParameters + err := s.client.Get(ctx, key, &icp) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("IngressClassParameters %v not found", key)} + } return nil, err } - if !exists { - return nil, ErrNotFound{fmt.Sprintf("IngressClassParameters %v not found", ingressClass.Spec.Parameters.Name)} - } - return params.(*kongv1alpha1.IngressClassParameters), nil + return &icp, nil } // GetGateway returns gateway resource having specified namespace and name. -func (s Store) GetGateway(namespace string, name string) (*gatewayv1beta1.Gateway, error) { - key := fmt.Sprintf("%v/%v", namespace, name) - obj, exists, err := s.stores.Gateway.GetByKey(key) +func (s Store) GetGateway(ctx context.Context, namespace string, name string) (*gatewayv1beta1.Gateway, error) { + var ( + gateway gatewayv1beta1.Gateway + key = client.ObjectKey{ + Namespace: namespace, + Name: name, + } + ) + + err := s.client.Get(ctx, key, &gateway) if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrNotFound{fmt.Sprintf("Gateway %v not found", key)} + } return nil, err } - if !exists { - return nil, ErrNotFound{fmt.Sprintf("Gateway %v not found", name)} - } - return obj.(*gatewayv1beta1.Gateway), nil + return &gateway, nil } // ListKongConsumers returns all KongConsumers filtered by the ingress.class @@ -888,9 +788,10 @@ func (s Store) ListKongConsumers(ctx context.Context) []*kongv1.KongConsumer { return nil } + handlingClass := s.getIngressClassHandling(ctx) for i := range consumerList.Items { plugin := consumerList.Items[i] - if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, handlingClass) { consumers = append(consumers, &plugin) } } @@ -919,9 +820,10 @@ func (s Store) ListGlobalKongPlugins(ctx context.Context) ([]*kongv1.KongPlugin, return nil, err } + handlingClass := s.getIngressClassHandling(ctx) for i := range pluginList.Items { plugin := pluginList.Items[i] - if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, handlingClass) { plugins = append(plugins, &plugin) } } @@ -949,9 +851,10 @@ func (s Store) ListGlobalKongClusterPlugins(ctx context.Context) ([]*kongv1.Kong return nil, err } + handlingClass := s.getIngressClassHandling(ctx) for i := range pluginList.Items { plugin := pluginList.Items[i] - if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, handlingClass) { plugins = append(plugins, &plugin) } } @@ -969,9 +872,10 @@ func (s Store) ListKongClusterPlugins(ctx context.Context) []*kongv1.KongCluster return nil } + handlingClass := s.getIngressClassHandling(ctx) for i := range pluginList.Items { plugin := pluginList.Items[i] - if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + if s.isValidIngressClass(&plugin.ObjectMeta, annotations.IngressClassKey, handlingClass) { plugins = append(plugins, &plugin) } } @@ -1004,16 +908,17 @@ func (s Store) ListCACerts(ctx context.Context) ([]*corev1.Secret, error) { secrets []*corev1.Secret secretList corev1.SecretList ) - err = s.client.List(context.TODO(), &secretList, &client.ListOptions{ + err = s.client.List(ctx, &secretList, &client.ListOptions{ LabelSelector: labels.NewSelector().Add(*req), }) if err != nil { return nil, err } + handlingClass := s.getIngressClassHandling(ctx) for i := range secretList.Items { secret := secretList.Items[i] - if s.isValidIngressClass(&secret.ObjectMeta, annotations.IngressClassKey, s.getIngressClassHandling()) { + if s.isValidIngressClass(&secret.ObjectMeta, annotations.IngressClassKey, handlingClass) { secrets = append(secrets, &secret) } } @@ -1034,8 +939,8 @@ func (s Store) networkingIngressV1Beta1(obj interface{}) *netv1beta1.Ingress { // getIngressClassHandling returns annotations.ExactOrEmptyClassMatch if an IngressClass is the default class, or // annotations.ExactClassMatch if the IngressClass is not default or does not exist. -func (s Store) getIngressClassHandling() annotations.ClassMatching { - class, err := s.GetIngressClassV1(context.TODO(), s.ingressClass) //nolint:contextcheck +func (s Store) getIngressClassHandling(ctx context.Context) annotations.ClassMatching { + class, err := s.GetIngressClassV1(ctx, s.ingressClass) if err != nil { s.logger.Debugf("IngressClass %s not found", s.ingressClass) return annotations.ExactClassMatch diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 322cc146c3..b27ea401a5 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -1,20 +1,17 @@ package store import ( + "context" "reflect" - "strings" "testing" "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" netv1beta1 "k8s.io/api/networking/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" ) @@ -66,79 +63,6 @@ func TestNetworkingIngressV1Beta1(t *testing.T) { } } -func TestCacheStoresGet(t *testing.T) { - t.Log("configuring some yaml objects to store in the cache") - svcYAML := []byte(`--- -apiVersion: v1 -kind: Service -metadata: - name: httpbin-deployment - namespace: default - labels: - app: httpbin -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: httpbin - type: ClusterIP -`) - ingYAML := []byte(`--- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: httpbin-ingress - namespace: default - annotations: - httpbin.ingress.kubernetes.io/rewrite-target: / - kubernetes.io/ingress.class: "kong" -spec: - rules: - - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: httpbin-deployment - port: - number: 80 -`) - - t.Log("creating a new cache store from object yaml files") - client := ctrlfake.NewClientBuilder().Build() - cs, err := NewCacheStoresFromObjYAML(client, svcYAML, ingYAML) // TODO(pmalek) - require.NoError(t, err) - - t.Log("verifying that the cache store doesnt try to retrieve unsupported object types") - _, exists, err := cs.Get(new(appsv1.Deployment)) - assert.Error(t, err) - assert.True(t, strings.Contains(err.Error(), "Deployment is not a supported cache object type")) - assert.False(t, exists) - - t.Log("verifying the integrity of the cache store") - // TODO(pmalek) - // assert.Len(t, cs.IngressV1.List(), 1) - // assert.Len(t, cs.Service.List(), 1) - // assert.Len(t, cs.IngressV1beta1.List(), 0) - assert.Len(t, cs.KongIngress.List(), 0) - _, exists, err = cs.Get(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: "doesntexist", Name: "doesntexist"}}) - assert.NoError(t, err) - assert.False(t, exists) - - t.Log("ensuring that we can Get() the objects back out of the cache store") - svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "httpbin-deployment"}} - ing := &netv1.Ingress{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "httpbin-ingress"}} - _, exists, err = cs.Get(svc) - assert.NoError(t, err) - assert.True(t, exists) - _, exists, err = cs.Get(ing) - assert.NoError(t, err) - assert.True(t, exists) -} - func TestGetIngressClassHandling(t *testing.T) { tests := []struct { name string @@ -191,7 +115,7 @@ func TestGetIngressClassHandling(t *testing.T) { t.Run(tt.name, func(t *testing.T) { s, err := NewFakeStore(tt.objs) require.NoError(t, err) - if got := s.(Store).getIngressClassHandling(); got != tt.want { + if got := s.(Store).getIngressClassHandling(context.TODO()); got != tt.want { t.Errorf("s.getIngressClassHandling() = %v, want %v", got, tt.want) } }) From 7d923c574bf4e940899da4b9a36e1a0c28ca72a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Thu, 6 Apr 2023 16:56:31 +0200 Subject: [PATCH 4/4] wip4 --- .golangci.yaml | 3 + .../generators/controllers/networking/main.go | 14 +- internal/adminapi/endpoints_test.go | 4 +- internal/adminapi/kong.go | 2 +- .../configuration/secret_controller.go | 8 +- .../configuration/zz_generated_controllers.go | 136 ++-- .../controllers/gateway/dataplane_client.go | 6 +- .../gateway/dataplane_mock_test.go | 6 +- .../controllers/gateway/gateway_controller.go | 14 +- .../controllers/gateway/gateway_utils_test.go | 4 +- .../gateway/grpcroute_controller.go | 12 +- .../gateway/httproute_controller.go | 12 +- .../gateway/referencegrant_controller.go | 8 +- .../controllers/gateway/route_utils_test.go | 14 +- .../gateway/tcproute_controller.go | 12 +- .../gateway/tlsroute_controller.go | 12 +- .../gateway/udproute_controller.go | 12 +- internal/controllers/knative/knative.go | 14 +- internal/controllers/reference/indexer.go | 5 +- internal/controllers/reference/reference.go | 8 +- internal/dataplane/kong_client.go | 29 +- internal/dataplane/kong_client_test.go | 4 +- internal/dataplane/kongstate/util_test.go | 87 ++- .../parser/ingressclassparemeters_test.go | 128 ++-- .../dataplane/parser/ingressrules_test.go | 38 +- internal/dataplane/parser/parser_test.go | 584 +++++++++++------- .../parser/translate_httproute_test.go | 6 +- .../parser/translate_knative_test.go | 12 +- .../parser/translate_kong_l4_test.go | 10 +- .../parser/translate_secrets_test.go | 71 ++- .../dataplane/parser/translate_utils_test.go | 2 +- internal/manager/telemetry/manager_test.go | 6 +- internal/meshdetect/detector_test.go | 8 +- internal/store/fake_store_test.go | 20 +- internal/store/store.go | 143 +---- 35 files changed, 799 insertions(+), 655 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index f0479600f5..fa8b531efb 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -75,6 +75,9 @@ linters-settings: alias: metav1 - pkg: sigs.k8s.io/gateway-api/apis/(v[\w\d]+) alias: gateway${1} + + - pkg: sigs.k8s.io/controller-runtime/pkg/client/fake + alias: ctrlclientfake gomodguard: blocked: modules: diff --git a/hack/generators/controllers/networking/main.go b/hack/generators/controllers/networking/main.go index 4773b923f9..082f225b89 100644 --- a/hack/generators/controllers/networking/main.go +++ b/hack/generators/controllers/networking/main.go @@ -528,11 +528,11 @@ func (r *{{.PackageAlias}}{{.Kind}}Reconciler) Reconcile(ctx context.Context, re obj.Name = req.Name {{if .NeedsUpdateReferences}} // remove reference record where the {{.Kind}} is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } {{end}} - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -543,16 +543,16 @@ func (r *{{.PackageAlias}}{{.Kind}}Reconciler) Reconcile(ctx context.Context, re log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "{{.Kind}}", "namespace", req.Namespace, "name", req.Name) {{if .NeedsUpdateReferences}} // remove reference record where the {{.Kind}} is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } {{end}} - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -574,14 +574,14 @@ func (r *{{.PackageAlias}}{{.Kind}}Reconciler) Reconcile(ctx context.Context, re if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } else { log.V(util.DebugLevel).Info("object has matching ingress class", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) } {{end}} // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } diff --git a/internal/adminapi/endpoints_test.go b/internal/adminapi/endpoints_test.go index 1a5bc98169..df2583f142 100644 --- a/internal/adminapi/endpoints_test.go +++ b/internal/adminapi/endpoints_test.go @@ -13,7 +13,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/controller-runtime/pkg/client" - fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" ) func TestAddressesFromEndpointSlice(t *testing.T) { @@ -537,7 +537,7 @@ func TestGetAdminAPIsForService(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - fakeClient := fakeclient.NewClientBuilder(). + fakeClient := ctrlclientfake.NewClientBuilder(). WithLists(tt.objects...). Build() diff --git a/internal/adminapi/kong.go b/internal/adminapi/kong.go index 0f01275243..7498877f78 100644 --- a/internal/adminapi/kong.go +++ b/internal/adminapi/kong.go @@ -78,7 +78,7 @@ func MakeHTTPClient(opts *HTTPClientOpts, kongAdminToken string) (*http.Client, var tlsConfig tls.Config if opts.TLSSkipVerify { - tlsConfig.InsecureSkipVerify = true + tlsConfig.InsecureSkipVerify = true //nolint:gosec } if opts.TLSServerName != "" { diff --git a/internal/controllers/configuration/secret_controller.go b/internal/controllers/configuration/secret_controller.go index 2953fad951..682a4ae24a 100644 --- a/internal/controllers/configuration/secret_controller.go +++ b/internal/controllers/configuration/secret_controller.go @@ -103,7 +103,7 @@ func (r *CoreV1SecretReconciler) Reconcile(ctx context.Context, req ctrl.Request if apierrors.IsNotFound(err) { secret.Namespace = req.Namespace secret.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(secret) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, secret) } return ctrl.Result{}, err } @@ -112,12 +112,12 @@ func (r *CoreV1SecretReconciler) Reconcile(ctx context.Context, req ctrl.Request // clean the object up if it's being deleted if !secret.DeletionTimestamp.IsZero() && time.Now().After(secret.DeletionTimestamp.Time) { log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "Secret", "namespace", req.Namespace, "name", req.Name) - objectExistsInCache, err := r.DataplaneClient.ObjectExists(secret) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, secret) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(secret); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, secret); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -126,7 +126,7 @@ func (r *CoreV1SecretReconciler) Reconcile(ctx context.Context, req ctrl.Request } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(secret); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, secret); err != nil { return ctrl.Result{}, err } diff --git a/internal/controllers/configuration/zz_generated_controllers.go b/internal/controllers/configuration/zz_generated_controllers.go index 21506815d9..6d0c2c2ec6 100644 --- a/internal/controllers/configuration/zz_generated_controllers.go +++ b/internal/controllers/configuration/zz_generated_controllers.go @@ -97,11 +97,11 @@ func (r *CoreV1ServiceReconciler) Reconcile(ctx context.Context, req ctrl.Reques obj.Name = req.Name // remove reference record where the Service is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -112,16 +112,16 @@ func (r *CoreV1ServiceReconciler) Reconcile(ctx context.Context, req ctrl.Reques log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "Service", "namespace", req.Namespace, "name", req.Name) // remove reference record where the Service is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -130,7 +130,7 @@ func (r *CoreV1ServiceReconciler) Reconcile(ctx context.Context, req ctrl.Reques } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // update reference relationship from the Service to other objects. @@ -193,7 +193,7 @@ func (r *CoreV1EndpointsReconciler) Reconcile(ctx context.Context, req ctrl.Requ obj.Namespace = req.Namespace obj.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -203,12 +203,12 @@ func (r *CoreV1EndpointsReconciler) Reconcile(ctx context.Context, req ctrl.Requ if !obj.DeletionTimestamp.IsZero() && time.Now().After(obj.DeletionTimestamp.Time) { log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "Endpoints", "namespace", req.Namespace, "name", req.Name) - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -217,7 +217,7 @@ func (r *CoreV1EndpointsReconciler) Reconcile(ctx context.Context, req ctrl.Requ } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } @@ -324,11 +324,11 @@ func (r *NetV1IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request obj.Name = req.Name // remove reference record where the Ingress is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -339,16 +339,16 @@ func (r *NetV1IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "Ingress", "namespace", req.Namespace, "name", req.Name) // remove reference record where the Ingress is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -370,14 +370,14 @@ func (r *NetV1IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } else { log.V(util.DebugLevel).Info("object has matching ingress class", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // update reference relationship from the Ingress to other objects. @@ -464,7 +464,7 @@ func (r *NetV1IngressClassReconciler) Reconcile(ctx context.Context, req ctrl.Re obj.Namespace = req.Namespace obj.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -474,12 +474,12 @@ func (r *NetV1IngressClassReconciler) Reconcile(ctx context.Context, req ctrl.Re if !obj.DeletionTimestamp.IsZero() && time.Now().After(obj.DeletionTimestamp.Time) { log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "IngressClass", "namespace", req.Namespace, "name", req.Name) - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -488,7 +488,7 @@ func (r *NetV1IngressClassReconciler) Reconcile(ctx context.Context, req ctrl.Re } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } @@ -595,11 +595,11 @@ func (r *NetV1Beta1IngressReconciler) Reconcile(ctx context.Context, req ctrl.Re obj.Name = req.Name // remove reference record where the Ingress is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -610,16 +610,16 @@ func (r *NetV1Beta1IngressReconciler) Reconcile(ctx context.Context, req ctrl.Re log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "Ingress", "namespace", req.Namespace, "name", req.Name) // remove reference record where the Ingress is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -641,14 +641,14 @@ func (r *NetV1Beta1IngressReconciler) Reconcile(ctx context.Context, req ctrl.Re if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } else { log.V(util.DebugLevel).Info("object has matching ingress class", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // update reference relationship from the Ingress to other objects. @@ -736,7 +736,7 @@ func (r *KongV1KongIngressReconciler) Reconcile(ctx context.Context, req ctrl.Re obj.Namespace = req.Namespace obj.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -746,12 +746,12 @@ func (r *KongV1KongIngressReconciler) Reconcile(ctx context.Context, req ctrl.Re if !obj.DeletionTimestamp.IsZero() && time.Now().After(obj.DeletionTimestamp.Time) { log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "KongIngress", "namespace", req.Namespace, "name", req.Name) - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -760,7 +760,7 @@ func (r *KongV1KongIngressReconciler) Reconcile(ctx context.Context, req ctrl.Re } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } @@ -815,11 +815,11 @@ func (r *KongV1KongPluginReconciler) Reconcile(ctx context.Context, req ctrl.Req obj.Name = req.Name // remove reference record where the KongPlugin is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -830,16 +830,16 @@ func (r *KongV1KongPluginReconciler) Reconcile(ctx context.Context, req ctrl.Req log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "KongPlugin", "namespace", req.Namespace, "name", req.Name) // remove reference record where the KongPlugin is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -848,7 +848,7 @@ func (r *KongV1KongPluginReconciler) Reconcile(ctx context.Context, req ctrl.Req } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // update reference relationship from the KongPlugin to other objects. @@ -949,11 +949,11 @@ func (r *KongV1KongClusterPluginReconciler) Reconcile(ctx context.Context, req c obj.Name = req.Name // remove reference record where the KongClusterPlugin is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -964,16 +964,16 @@ func (r *KongV1KongClusterPluginReconciler) Reconcile(ctx context.Context, req c log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "KongClusterPlugin", "namespace", req.Namespace, "name", req.Name) // remove reference record where the KongClusterPlugin is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -995,14 +995,14 @@ func (r *KongV1KongClusterPluginReconciler) Reconcile(ctx context.Context, req c if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } else { log.V(util.DebugLevel).Info("object has matching ingress class", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // update reference relationship from the KongClusterPlugin to other objects. @@ -1103,11 +1103,11 @@ func (r *KongV1KongConsumerReconciler) Reconcile(ctx context.Context, req ctrl.R obj.Name = req.Name // remove reference record where the KongConsumer is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -1118,16 +1118,16 @@ func (r *KongV1KongConsumerReconciler) Reconcile(ctx context.Context, req ctrl.R log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "KongConsumer", "namespace", req.Namespace, "name", req.Name) // remove reference record where the KongConsumer is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -1149,14 +1149,14 @@ func (r *KongV1KongConsumerReconciler) Reconcile(ctx context.Context, req ctrl.R if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } else { log.V(util.DebugLevel).Info("object has matching ingress class", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // update reference relationship from the KongConsumer to other objects. @@ -1273,11 +1273,11 @@ func (r *KongV1Beta1TCPIngressReconciler) Reconcile(ctx context.Context, req ctr obj.Name = req.Name // remove reference record where the TCPIngress is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -1288,16 +1288,16 @@ func (r *KongV1Beta1TCPIngressReconciler) Reconcile(ctx context.Context, req ctr log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "TCPIngress", "namespace", req.Namespace, "name", req.Name) // remove reference record where the TCPIngress is the referrer - if err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { + if err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj); err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -1319,14 +1319,14 @@ func (r *KongV1Beta1TCPIngressReconciler) Reconcile(ctx context.Context, req ctr if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } else { log.V(util.DebugLevel).Info("object has matching ingress class", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // update reference relationship from the TCPIngress to other objects. @@ -1466,7 +1466,7 @@ func (r *KongV1Beta1UDPIngressReconciler) Reconcile(ctx context.Context, req ctr obj.Namespace = req.Namespace obj.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -1476,12 +1476,12 @@ func (r *KongV1Beta1UDPIngressReconciler) Reconcile(ctx context.Context, req ctr if !obj.DeletionTimestamp.IsZero() && time.Now().After(obj.DeletionTimestamp.Time) { log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "UDPIngress", "namespace", req.Namespace, "name", req.Name) - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -1503,14 +1503,14 @@ func (r *KongV1Beta1UDPIngressReconciler) Reconcile(ctx context.Context, req ctr if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } else { log.V(util.DebugLevel).Info("object has matching ingress class", "namespace", req.Namespace, "name", req.Name, "class", r.IngressClassName) } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // if status updates are enabled report the status for the object @@ -1587,7 +1587,7 @@ func (r *KongV1Alpha1IngressClassParametersReconciler) Reconcile(ctx context.Con obj.Namespace = req.Namespace obj.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -1597,12 +1597,12 @@ func (r *KongV1Alpha1IngressClassParametersReconciler) Reconcile(ctx context.Con if !obj.DeletionTimestamp.IsZero() && time.Now().After(obj.DeletionTimestamp.Time) { log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "IngressClassParameters", "namespace", req.Namespace, "name", req.Name) - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -1611,7 +1611,7 @@ func (r *KongV1Alpha1IngressClassParametersReconciler) Reconcile(ctx context.Con } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } diff --git a/internal/controllers/gateway/dataplane_client.go b/internal/controllers/gateway/dataplane_client.go index be06870683..c170a7ad84 100644 --- a/internal/controllers/gateway/dataplane_client.go +++ b/internal/controllers/gateway/dataplane_client.go @@ -1,6 +1,8 @@ package gateway import ( + "context" + "sigs.k8s.io/controller-runtime/pkg/client" k8sobj "github.com/kong/kubernetes-ingress-controller/v2/internal/util/kubernetes/object" @@ -21,6 +23,6 @@ type DataPlane interface { // DataPlaneClient is a common client interface that is used by reconcilers to interact // with the dataplane to perform CRUD operations on provided objects. type DataPlaneClient interface { - UpdateObject(obj client.Object) error - DeleteObject(obj client.Object) error + UpdateObject(ctx context.Context, obj client.Object) error + DeleteObject(ctx context.Context, obj client.Object) error } diff --git a/internal/controllers/gateway/dataplane_mock_test.go b/internal/controllers/gateway/dataplane_mock_test.go index 33128889d6..2e51ff11fc 100644 --- a/internal/controllers/gateway/dataplane_mock_test.go +++ b/internal/controllers/gateway/dataplane_mock_test.go @@ -1,6 +1,8 @@ package gateway import ( + "context" + "sigs.k8s.io/controller-runtime/pkg/client" k8sobj "github.com/kong/kubernetes-ingress-controller/v2/internal/util/kubernetes/object" @@ -15,11 +17,11 @@ type DataplaneMock struct { ObjectsStatuses map[string]map[string]k8sobj.ConfigurationStatus } -func (d DataplaneMock) UpdateObject(_ client.Object) error { +func (d DataplaneMock) UpdateObject(_ context.Context, _ client.Object) error { return nil } -func (d DataplaneMock) DeleteObject(_ client.Object) error { +func (d DataplaneMock) DeleteObject(_ context.Context, _ client.Object) error { return nil } diff --git a/internal/controllers/gateway/gateway_controller.go b/internal/controllers/gateway/gateway_controller.go index bbadc3e22d..d641c9321b 100644 --- a/internal/controllers/gateway/gateway_controller.go +++ b/internal/controllers/gateway/gateway_controller.go @@ -296,12 +296,12 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct gateway.Namespace = req.Namespace gateway.Name = req.Name // delete reference relationships where the gateway is the referrer. - err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, gateway) + err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, gateway) if err != nil { return ctrl.Result{}, err } debug(log, gateway, "reconciliation triggered but gateway does not exist, deleting it in dataplane") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(gateway) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, gateway) } return ctrl.Result{Requeue: true}, err } @@ -316,11 +316,11 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct if err := r.Client.Get(ctx, client.ObjectKey{Name: string(gateway.Spec.GatewayClassName)}, gwc); err != nil { debug(log, gateway, "could not retrieve gatewayclass for gateway", "gatewayclass", string(gateway.Spec.GatewayClassName)) // delete reference relationships where the gateway is the referrer, as we will not process the gateway. - err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, gateway) + err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, gateway) if err != nil { return ctrl.Result{}, err } - if err := r.DataplaneClient.DeleteObject(gateway); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, gateway); err != nil { debug(log, gateway, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } @@ -330,11 +330,11 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct if gwc.Spec.ControllerName != GetControllerName() { debug(log, gateway, "unsupported gatewayclass controllername, ignoring", "gatewayclass", gwc.Name, "controllername", gwc.Spec.ControllerName) // delete reference relationships where the gateway is the referrer, as we will not process the gateway. - err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, gateway) + err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, gateway) if err != nil { return ctrl.Result{}, err } - if err := r.DataplaneClient.DeleteObject(gateway); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, gateway); err != nil { debug(log, gateway, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } @@ -365,7 +365,7 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct // reconcileUnmanagedGateway has side effects and modifies the referenced gateway object. dataplane updates must // happen afterwards if err == nil { - if err := r.DataplaneClient.UpdateObject(gateway); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, gateway); err != nil { debug(log, gateway, "failed to update object in data-plane, requeueing") return result, err } diff --git a/internal/controllers/gateway/gateway_utils_test.go b/internal/controllers/gateway/gateway_utils_test.go index 61feeafa7d..080b022017 100644 --- a/internal/controllers/gateway/gateway_utils_test.go +++ b/internal/controllers/gateway/gateway_utils_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client/fake" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/util/builder" @@ -114,7 +114,7 @@ func TestGetListenerSupportedRouteKinds(t *testing.T) { func TestGetListenerStatus_no_duplicated_condition(t *testing.T) { ctx := context.Background() - client := fake.NewClientBuilder().Build() + client := ctrlclientfake.NewClientBuilder().Build() statuses, err := getListenerStatus(ctx, &Gateway{ Spec: gatewayv1beta1.GatewaySpec{ diff --git a/internal/controllers/gateway/grpcroute_controller.go b/internal/controllers/gateway/grpcroute_controller.go index 35adca5fbe..2978bc3f12 100644 --- a/internal/controllers/gateway/grpcroute_controller.go +++ b/internal/controllers/gateway/grpcroute_controller.go @@ -250,7 +250,7 @@ func (r *GRPCRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( debug(log, grpcroute, "object does not exist, ensuring it is not present in the proxy cache") grpcroute.Namespace = req.Namespace grpcroute.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(grpcroute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, grpcroute) } // for any error other than 404, requeue @@ -265,12 +265,12 @@ func (r *GRPCRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( debug(log, grpcroute, "checking deletion timestamp") if grpcroute.DeletionTimestamp != nil { debug(log, grpcroute, "grpcroute is being deleted, re-configuring data-plane") - if err := r.DataplaneClient.DeleteObject(grpcroute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, grpcroute); err != nil { debug(log, grpcroute, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } debug(log, grpcroute, "ensured object was removed from the data-plane (if ever present)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(grpcroute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, grpcroute) } // we need to pull the Gateway parent objects for the grpcroute to verify @@ -300,7 +300,7 @@ func (r *GRPCRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // ensure that it's removed from the proxy cache to avoid orphaned data-plane // configurations. debug(log, grpcroute, "ensuring that dataplane is updated to remove unsupported route (if applicable)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(grpcroute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, grpcroute) } return ctrl.Result{}, err } @@ -319,13 +319,13 @@ func (r *GRPCRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if isRouteAccepted(gateways) { // if the gateways are ready, and the GRPCRoute is destined for them, ensure that // the object is pushed to the dataplane. - if err := r.DataplaneClient.UpdateObject(grpcroute); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, grpcroute); err != nil { debug(log, grpcroute, "failed to update object in data-plane, requeueing") return ctrl.Result{}, err } } else { // route is not accepted, remove it from kong store - if err := r.DataplaneClient.DeleteObject(grpcroute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, grpcroute); err != nil { debug(log, grpcroute, "failed to delete object in data-plane, requeueing") return ctrl.Result{}, err } diff --git a/internal/controllers/gateway/httproute_controller.go b/internal/controllers/gateway/httproute_controller.go index f594878be0..a1c75249ef 100644 --- a/internal/controllers/gateway/httproute_controller.go +++ b/internal/controllers/gateway/httproute_controller.go @@ -307,7 +307,7 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( debug(log, httproute, "object does not exist, ensuring it is not present in the proxy cache") httproute.Namespace = req.Namespace httproute.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(httproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, httproute) } // for any error other than 404, requeue @@ -322,12 +322,12 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( debug(log, httproute, "checking deletion timestamp") if httproute.DeletionTimestamp != nil { debug(log, httproute, "httproute is being deleted, re-configuring data-plane") - if err := r.DataplaneClient.DeleteObject(httproute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, httproute); err != nil { debug(log, httproute, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } debug(log, httproute, "ensured object was removed from the data-plane (if ever present)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(httproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, httproute) } // we need to pull the Gateway parent objects for the HTTPRoute to verify @@ -357,7 +357,7 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // ensure that it's removed from the proxy cache to avoid orphaned data-plane // configurations. debug(log, httproute, "ensuring that dataplane is updated to remove unsupported route (if applicable)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(httproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, httproute) } return ctrl.Result{}, err } @@ -381,13 +381,13 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if isRouteAccepted(gateways) && err == nil { // if the gateways are ready, and the HTTPRoute is destined for them, ensure that // the object is pushed to the dataplane. - if err := r.DataplaneClient.UpdateObject(filteredHTTPRoute); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, filteredHTTPRoute); err != nil { debug(log, httproute, "failed to update object in data-plane, requeueing") return ctrl.Result{}, err } } else { // route is not accepted, remove it from kong store - if err := r.DataplaneClient.DeleteObject(httproute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, httproute); err != nil { debug(log, httproute, "failed to delete object in data-plane, requeueing") return ctrl.Result{}, err } diff --git a/internal/controllers/gateway/referencegrant_controller.go b/internal/controllers/gateway/referencegrant_controller.go index 0b4a2b6f61..1255c59fcb 100644 --- a/internal/controllers/gateway/referencegrant_controller.go +++ b/internal/controllers/gateway/referencegrant_controller.go @@ -78,7 +78,7 @@ func (r *ReferenceGrantReconciler) Reconcile(ctx context.Context, req ctrl.Reque debug(log, grant, "object does not exist, ensuring it is not present in the proxy cache") grant.Namespace = req.Namespace grant.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(grant) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, grant) } // for any error other than 404, requeue @@ -89,15 +89,15 @@ func (r *ReferenceGrantReconciler) Reconcile(ctx context.Context, req ctrl.Reque debug(log, grant, "checking deletion timestamp") if grant.DeletionTimestamp != nil { debug(log, grant, "referencegrant is being deleted, re-configuring data-plane") - if err := r.DataplaneClient.DeleteObject(grant); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, grant); err != nil { debug(log, grant, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } debug(log, grant, "ensured object was removed from the data-plane (if ever present)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(grant) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, grant) } - if err := r.DataplaneClient.UpdateObject(grant); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, grant); err != nil { debug(log, grant, "failed to update object in data-plane, requeueing") return ctrl.Result{}, err } diff --git a/internal/controllers/gateway/route_utils_test.go b/internal/controllers/gateway/route_utils_test.go index b6740529c5..a71aa717a4 100644 --- a/internal/controllers/gateway/route_utils_test.go +++ b/internal/controllers/gateway/route_utils_test.go @@ -15,7 +15,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" @@ -541,7 +541,7 @@ func Test_getSupportedGatewayForRoute(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - fakeClient := fakeclient. + fakeClient := ctrlclientfake. NewClientBuilder(). WithScheme(scheme.Scheme). WithObjects(tt.objects...). @@ -749,7 +749,7 @@ func Test_getSupportedGatewayForRoute(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - fakeClient := fakeclient. + fakeClient := ctrlclientfake. NewClientBuilder(). WithScheme(scheme.Scheme). WithObjects(tt.objects...). @@ -936,7 +936,7 @@ func Test_getSupportedGatewayForRoute(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - fakeClient := fakeclient. + fakeClient := ctrlclientfake. NewClientBuilder(). WithScheme(scheme.Scheme). WithObjects(tt.objects...). @@ -1164,7 +1164,7 @@ func Test_getSupportedGatewayForRoute(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - fakeClient := fakeclient. + fakeClient := ctrlclientfake. NewClientBuilder(). WithScheme(scheme.Scheme). WithObjects(tt.objects...). @@ -1195,7 +1195,7 @@ func Test_getSupportedGatewayForRoute(t *testing.T) { }, } t.Run("invalid parentRef kind rejected", func(t *testing.T) { - fakeClient := fakeclient. + fakeClient := ctrlclientfake. NewClientBuilder(). WithScheme(scheme.Scheme). Build() @@ -1801,7 +1801,7 @@ func Test_ensureParentsProgrammedCondition(t *testing.T) { gateways = tc.gatewayFunc() ) - fakeClient := fakeclient. + fakeClient := ctrlclientfake. NewClientBuilder(). WithScheme(scheme.Scheme). WithObjects(httproute). diff --git a/internal/controllers/gateway/tcproute_controller.go b/internal/controllers/gateway/tcproute_controller.go index 56c4796b8e..90b367f8db 100644 --- a/internal/controllers/gateway/tcproute_controller.go +++ b/internal/controllers/gateway/tcproute_controller.go @@ -246,7 +246,7 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c debug(log, tcproute, "object does not exist, ensuring it is not present in the proxy cache") tcproute.Namespace = req.Namespace tcproute.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(tcproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, tcproute) } // for any error other than 404, requeue @@ -261,12 +261,12 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c debug(log, tcproute, "checking deletion timestamp") if tcproute.DeletionTimestamp != nil { debug(log, tcproute, "tcproute is being deleted, re-configuring data-plane") - if err := r.DataplaneClient.DeleteObject(tcproute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, tcproute); err != nil { debug(log, tcproute, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } debug(log, tcproute, "ensured object was removed from the data-plane (if ever present)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(tcproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, tcproute) } // we need to pull the Gateway parent objects for the TCPRoute to verify @@ -296,7 +296,7 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // ensure that it's removed from the proxy cache to avoid orphaned data-plane // configurations. debug(log, tcproute, "ensuring that dataplane is updated to remove unsupported route (if applicable)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(tcproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, tcproute) } return ctrl.Result{}, err } @@ -315,7 +315,7 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if isRouteAccepted(gateways) { // if the gateways are ready, and the TCPRoute is destined for them, ensure that // the object is pushed to the dataplane. - if err := r.DataplaneClient.UpdateObject(tcproute); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, tcproute); err != nil { debug(log, tcproute, "failed to update object in data-plane, requeueing") return ctrl.Result{}, err } @@ -330,7 +330,7 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c } } else { // route is not accepted, remove it from kong store - if err := r.DataplaneClient.DeleteObject(tcproute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, tcproute); err != nil { debug(log, tcproute, "failed to delete object in data-plane, requeueing") return ctrl.Result{}, err } diff --git a/internal/controllers/gateway/tlsroute_controller.go b/internal/controllers/gateway/tlsroute_controller.go index 06a0675caf..03af0752c7 100644 --- a/internal/controllers/gateway/tlsroute_controller.go +++ b/internal/controllers/gateway/tlsroute_controller.go @@ -246,7 +246,7 @@ func (r *TLSRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c debug(log, tlsroute, "object does not exist, ensuring it is not present in the proxy cache") tlsroute.Namespace = req.Namespace tlsroute.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(tlsroute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, tlsroute) } // for any error other than 404, requeue @@ -261,12 +261,12 @@ func (r *TLSRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c debug(log, tlsroute, "checking deletion timestamp") if tlsroute.DeletionTimestamp != nil { debug(log, tlsroute, "tlsroute is being deleted, re-configuring data-plane") - if err := r.DataplaneClient.DeleteObject(tlsroute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, tlsroute); err != nil { debug(log, tlsroute, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } debug(log, tlsroute, "ensured object was removed from the data-plane (if ever present)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(tlsroute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, tlsroute) } // we need to pull the Gateway parent objects for the TLSRoute to verify @@ -296,7 +296,7 @@ func (r *TLSRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // ensure that it's removed from the proxy cache to avoid orphaned data-plane // configurations. debug(log, tlsroute, "ensuring that dataplane is updated to remove unsupported route (if applicable)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(tlsroute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, tlsroute) } return ctrl.Result{}, err } @@ -315,13 +315,13 @@ func (r *TLSRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if isRouteAccepted(gateways) { // if the gateways are ready, and the TLSRoute is destined for them, ensure that // the object is pushed to the dataplane. - if err := r.DataplaneClient.UpdateObject(tlsroute); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, tlsroute); err != nil { debug(log, tlsroute, "failed to update object in data-plane, requeueing") return ctrl.Result{}, err } } else { // route is not accepted, remove it from kong store - if err := r.DataplaneClient.DeleteObject(tlsroute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, tlsroute); err != nil { debug(log, tlsroute, "failed to delete object in data-plane, requeueing") return ctrl.Result{}, err } diff --git a/internal/controllers/gateway/udproute_controller.go b/internal/controllers/gateway/udproute_controller.go index 0f3a86f2be..bf3294a5f5 100644 --- a/internal/controllers/gateway/udproute_controller.go +++ b/internal/controllers/gateway/udproute_controller.go @@ -246,7 +246,7 @@ func (r *UDPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c debug(log, udproute, "object does not exist, ensuring it is not present in the proxy cache") udproute.Namespace = req.Namespace udproute.Name = req.Name - return ctrl.Result{}, r.DataplaneClient.DeleteObject(udproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, udproute) } // for any error other than 404, requeue @@ -261,12 +261,12 @@ func (r *UDPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c debug(log, udproute, "checking deletion timestamp") if udproute.DeletionTimestamp != nil { debug(log, udproute, "udproute is being deleted, re-configuring data-plane") - if err := r.DataplaneClient.DeleteObject(udproute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, udproute); err != nil { debug(log, udproute, "failed to delete object from data-plane, requeuing") return ctrl.Result{}, err } debug(log, udproute, "ensured object was removed from the data-plane (if ever present)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(udproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, udproute) } // we need to pull the Gateway parent objects for the UDPRoute to verify @@ -296,7 +296,7 @@ func (r *UDPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // ensure that it's removed from the proxy cache to avoid orphaned data-plane // configurations. debug(log, udproute, "ensuring that dataplane is updated to remove unsupported route (if applicable)") - return ctrl.Result{}, r.DataplaneClient.DeleteObject(udproute) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, udproute) } return ctrl.Result{}, err } @@ -315,7 +315,7 @@ func (r *UDPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if isRouteAccepted(gateways) { // if the gateways are ready, and the UDPRoute is destined for them, ensure that // the object is pushed to the dataplane. - if err := r.DataplaneClient.UpdateObject(udproute); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, udproute); err != nil { debug(log, udproute, "failed to update object in data-plane, requeueing") return ctrl.Result{}, err } @@ -330,7 +330,7 @@ func (r *UDPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c } } else { // route is not accepted, remove it from kong store - if err := r.DataplaneClient.DeleteObject(udproute); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, udproute); err != nil { debug(log, udproute, "failed to delete object in data-plane, requeueing") return ctrl.Result{}, err } diff --git a/internal/controllers/knative/knative.go b/internal/controllers/knative/knative.go index fb8f75fb1a..ac65abb802 100644 --- a/internal/controllers/knative/knative.go +++ b/internal/controllers/knative/knative.go @@ -129,11 +129,11 @@ func (r *Knativev1alpha1IngressReconciler) Reconcile(ctx context.Context, req ct obj.Namespace = req.Namespace obj.Name = req.Name - err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj) + err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj) if err != nil { return ctrl.Result{}, err } - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } return ctrl.Result{}, err } @@ -142,17 +142,17 @@ func (r *Knativev1alpha1IngressReconciler) Reconcile(ctx context.Context, req ct // clean the object up if it's being deleted if !obj.DeletionTimestamp.IsZero() && time.Now().After(obj.DeletionTimestamp.Time) { log.V(util.DebugLevel).Info("resource is being deleted, its configuration will be removed", "type", "Ingress", "namespace", req.Namespace, "name", req.Name) - err := ctrlref.DeleteReferencesByReferrer(r.ReferenceIndexers, r.DataplaneClient, obj) + err := ctrlref.DeleteReferencesByReferrer(ctx, r.ReferenceIndexers, r.DataplaneClient, obj) if err != nil { return ctrl.Result{}, err } - objectExistsInCache, err := r.DataplaneClient.ObjectExists(obj) + objectExistsInCache, err := r.DataplaneClient.ObjectExists(ctx, obj) if err != nil { return ctrl.Result{}, err } if objectExistsInCache { - if err := r.DataplaneClient.DeleteObject(obj); err != nil { + if err := r.DataplaneClient.DeleteObject(ctx, obj); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil // wait until the object is no longer present in the cache @@ -173,7 +173,7 @@ func (r *Knativev1alpha1IngressReconciler) Reconcile(ctx context.Context, req ct // if the object is not configured with our ingress.class, then we need to ensure it's removed from the cache if !ctrlutils.MatchesIngressClass(obj, r.IngressClassName, ctrlutils.IsDefaultIngressClass(class)) { log.V(util.DebugLevel).Info("object missing ingress class, ensuring it's removed from configuration", "namespace", req.Namespace, "name", req.Name) - return ctrl.Result{}, r.DataplaneClient.DeleteObject(obj) + return ctrl.Result{}, r.DataplaneClient.DeleteObject(ctx, obj) } // update reference records for secrets referred by the ingress @@ -195,7 +195,7 @@ func (r *Knativev1alpha1IngressReconciler) Reconcile(ctx context.Context, req ct } // update the kong Admin API with the changes - if err := r.DataplaneClient.UpdateObject(obj); err != nil { + if err := r.DataplaneClient.UpdateObject(ctx, obj); err != nil { return ctrl.Result{}, err } // if status updates are enabled report the status for the object diff --git a/internal/controllers/reference/indexer.go b/internal/controllers/reference/indexer.go index f35f8a8eb2..a27635b793 100644 --- a/internal/controllers/reference/indexer.go +++ b/internal/controllers/reference/indexer.go @@ -1,6 +1,7 @@ package reference import ( + "context" "fmt" "k8s.io/client-go/tools/cache" @@ -155,13 +156,13 @@ func (c CacheIndexers) DeleteReferencesByReferrer(referrer client.Object) error // DeleteObjectIfNotReferred deletes object from object cach by dataplaneClient // the object is not referenced in reference cache. -func (c CacheIndexers) DeleteObjectIfNotReferred(obj client.Object, dataplaneClient *dataplane.KongClient) error { +func (c CacheIndexers) DeleteObjectIfNotReferred(ctx context.Context, obj client.Object, dataplaneClient *dataplane.KongClient) error { referred, err := c.ObjectReferred(obj) if err != nil { return err } if !referred { - return dataplaneClient.DeleteObject(obj) + return dataplaneClient.DeleteObject(ctx, obj) } return nil } diff --git a/internal/controllers/reference/reference.go b/internal/controllers/reference/reference.go index cb9a807a1d..aff3a8ccf5 100644 --- a/internal/controllers/reference/reference.go +++ b/internal/controllers/reference/reference.go @@ -45,7 +45,7 @@ func UpdateReferencesToSecret( return err } - if err := dataplaneClient.UpdateObject(secret); err != nil { + if err := dataplaneClient.UpdateObject(ctx, secret); err != nil { return err } } @@ -103,7 +103,7 @@ func removeOutdatedReferencesToSecret( } } - if err := indexers.DeleteObjectIfNotReferred(obj, dataplaneClient); err != nil { + if err := indexers.DeleteObjectIfNotReferred(ctx, obj, dataplaneClient); err != nil { return err } } @@ -114,7 +114,7 @@ func removeOutdatedReferencesToSecret( // DeleteReferencesByReferrer deletes all reference records with specified referrer // in reference cache. // If the affected secret is not referred by any other objects, it deletes the secret in object cache. -func DeleteReferencesByReferrer(indexers CacheIndexers, dataplaneClient *dataplane.KongClient, referrer client.Object) error { +func DeleteReferencesByReferrer(ctx context.Context, indexers CacheIndexers, dataplaneClient *dataplane.KongClient, referrer client.Object) error { referents, err := indexers.ListReferredObjects(referrer) if err != nil { return err @@ -134,7 +134,7 @@ func DeleteReferencesByReferrer(indexers CacheIndexers, dataplaneClient *datapla if !(gvk.Group == corev1.GroupName && gvk.Version == VersionV1 && gvk.Kind == KindSecret) { continue } - err := indexers.DeleteObjectIfNotReferred(referent, dataplaneClient) + err := indexers.DeleteObjectIfNotReferred(ctx, referent, dataplaneClient) if err != nil { return err } diff --git a/internal/dataplane/kong_client.go b/internal/dataplane/kong_client.go index 625ac165c9..47478143f4 100644 --- a/internal/dataplane/kong_client.go +++ b/internal/dataplane/kong_client.go @@ -75,10 +75,6 @@ type KongClient struct { // requests to the data-plane to receive a response. requestTimeout time.Duration - // cache is the Kubernetes object cache which is used to list Kubernetes - // objects for parsing into Kong objects. - cache *store.CacheStores - // kongConfig is the client configuration for the Kong Admin API kongConfig sendconfig.Config @@ -157,14 +153,12 @@ func NewKongClient( configChangeDetector sendconfig.ConfigurationChangeDetector, ) (*KongClient, error) { // build the client object - cache := store.NewCacheStores(client) c := &KongClient{ logger: logger, ingressClass: ingressClass, requestTimeout: timeout, diagnostic: diagnostic, prometheusMetrics: metrics.NewCtrlFuncMetrics(), - cache: &cache, client: client, kongConfig: kongConfig, eventRecorder: eventRecorder, @@ -185,8 +179,8 @@ func NewKongClient( // UpdateObject accepts a Kubernetes controller-runtime client.Object and adds/updates that to the configuration cache. // It will be asynchronously converted into the upstream Kong DSL and applied to the Kong Admin API. // A status will later be added to the object whether the configuration update succeeds or fails. -func (c *KongClient) UpdateObject(obj client.Object) error { - return c.client.Update(context.TODO(), obj) +func (c *KongClient) UpdateObject(ctx context.Context, obj client.Object) error { + return c.client.Update(ctx, obj) } // DeleteObject accepts a Kubernetes controller-runtime client.Object and removes it from the configuration. @@ -194,8 +188,8 @@ func (c *KongClient) UpdateObject(obj client.Object) error { // A status will later be added to the object whether the configuration update succeeds or fails. // // The implementation will ignore deletions on objects that are not present, so in those cases this is a no-op. -func (c *KongClient) DeleteObject(obj client.Object) error { - err := c.client.Delete(context.TODO(), obj) +func (c *KongClient) DeleteObject(ctx context.Context, obj client.Object) error { + err := c.client.Delete(ctx, obj) if apierrors.IsNotFound(err) { return nil } @@ -203,9 +197,12 @@ func (c *KongClient) DeleteObject(obj client.Object) error { } // ObjectExists indicates whether or not any version of the provided object is already present in the proxy. -func (c *KongClient) ObjectExists(obj client.Object) (bool, error) { - err := c.client.Get(context.TODO(), client.ObjectKeyFromObject(obj), obj) - if apierrors.IsNotFound(err) { +func (c *KongClient) ObjectExists(ctx context.Context, obj client.Object) (bool, error) { + err := c.client.Get(ctx, client.ObjectKeyFromObject(obj), obj) + if err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } return false, err } return true, nil @@ -390,9 +387,9 @@ func (c *KongClient) DBMode() string { return c.dbmode } -// Update parses the Cache present in the client and converts current -// Kubernetes state into Kong objects and state, and then ships the -// resulting configuration to the data-plane (Kong Admin API). +// Update parses the objects, fetched using the provided manager's client, +// converts current Kubernetes state into Kong objects and state and then ships +// the resulting configuration to the data-plane (Kong Admin API). func (c *KongClient) Update(ctx context.Context) error { c.lock.Lock() defer c.lock.Unlock() diff --git a/internal/dataplane/kong_client_test.go b/internal/dataplane/kong_client_test.go index 3e9ea8fc57..38dd17daac 100644 --- a/internal/dataplane/kong_client_test.go +++ b/internal/dataplane/kong_client_test.go @@ -22,7 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" - ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/adminapi" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane" @@ -425,7 +425,7 @@ func setupTestKongClient( config := sendconfig.Config{} eventRecorder := record.NewFakeRecorder(0) dbMode := "off" - client := ctrlfake.NewClientBuilder().Build() + client := ctrlclientfake.NewClientBuilder().Build() kongClient, err := dataplane.NewKongClient( logger, diff --git a/internal/dataplane/kongstate/util_test.go b/internal/dataplane/kongstate/util_test.go index 25e55b8384..1ac6b3418b 100644 --- a/internal/dataplane/kongstate/util_test.go +++ b/internal/dataplane/kongstate/util_test.go @@ -7,12 +7,15 @@ import ( "github.com/kong/go-kong/kong" "github.com/samber/lo" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" @@ -20,6 +23,7 @@ import ( "github.com/kong/kubernetes-ingress-controller/v2/internal/store" "github.com/kong/kubernetes-ingress-controller/v2/internal/util" configurationv1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" + "github.com/kong/kubernetes-ingress-controller/v2/pkg/clientset/fake" ) func TestKongPluginFromK8SClusterPlugin(t *testing.T) { @@ -307,12 +311,18 @@ func TestGetKongIngressForServices(t *testing.T) { }{ { name: "when no services are provided, no KongIngress will be provided", - kongIngresses: []*configurationv1.KongIngress{{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-kongingress1", - Namespace: corev1.NamespaceDefault, + kongIngresses: []*configurationv1.KongIngress{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-kongingress1", + Namespace: corev1.NamespaceDefault, + }, }, - }}, + }, }, { name: "when none of the provided services have attached KongIngress resources, no KongIngress resources will be provided", @@ -330,12 +340,18 @@ func TestGetKongIngressForServices(t *testing.T) { }, }, }, - kongIngresses: []*configurationv1.KongIngress{{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-kongingress1", - Namespace: corev1.NamespaceDefault, + kongIngresses: []*configurationv1.KongIngress{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-kongingress1", + Namespace: corev1.NamespaceDefault, + }, }, - }}, + }, }, { name: "if at least one KongIngress resource is attached to a Service, it will be returned", @@ -358,12 +374,20 @@ func TestGetKongIngressForServices(t *testing.T) { }, kongIngresses: []*configurationv1.KongIngress{ { + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress1", Namespace: corev1.NamespaceDefault, }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress2", Namespace: corev1.NamespaceDefault, @@ -371,6 +395,10 @@ func TestGetKongIngressForServices(t *testing.T) { }, }, expectedKongIngress: &configurationv1.KongIngress{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress2", Namespace: corev1.NamespaceDefault, @@ -412,18 +440,30 @@ func TestGetKongIngressForServices(t *testing.T) { }, kongIngresses: []*configurationv1.KongIngress{ { + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress1", Namespace: corev1.NamespaceDefault, }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress2", Namespace: corev1.NamespaceDefault, }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress3", Namespace: corev1.NamespaceDefault, @@ -431,6 +471,10 @@ func TestGetKongIngressForServices(t *testing.T) { }, }, expectedKongIngress: &configurationv1.KongIngress{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongIngress", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-kongingress2", Namespace: corev1.NamespaceDefault, @@ -441,13 +485,22 @@ func TestGetKongIngressForServices(t *testing.T) { }, } { t.Run(tt.name, func(t *testing.T) { - storer, err := store.NewFakeStore(store.FakeObjects{ - KongIngresses: tt.kongIngresses, - Services: lo.Values(tt.services), - }) - require.NoError(t, err) + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + client := ctrlclientfake.NewClientBuilder(). + WithObjects( + append( + lo.MapToSlice(tt.services, func(k string, v *corev1.Service) client.Object { + return v + }), + lo.Map(tt.kongIngresses, func(ki *configurationv1.KongIngress, _ int) client.Object { + return ki + })..., + )..., + ). + Build() + storer := store.New(client, "dummy", logrus.New()) - kongIngress, err := getKongIngressForServices(context.TODO(), storer, tt.services) + kongIngress, err := getKongIngressForServices(context.TODO(), storer, tt.services) if tt.expectedError == nil { assert.Equal(t, tt.expectedKongIngress, kongIngress) } else { @@ -574,7 +627,7 @@ func TestGetKongIngressFromObjectMeta(t *testing.T) { require.NoError(t, err) obj := util.FromK8sObject(tt.route) - kongIngress, err := getKongIngressFromObjectMeta(context.TODO(), storer, obj) + kongIngress, err := getKongIngressFromObjectMeta(context.TODO(), storer, obj) if tt.expectedError == nil { require.NoError(t, err) diff --git a/internal/dataplane/parser/ingressclassparemeters_test.go b/internal/dataplane/parser/ingressclassparemeters_test.go index da74073db2..b830ef4b31 100644 --- a/internal/dataplane/parser/ingressclassparemeters_test.go +++ b/internal/dataplane/parser/ingressclassparemeters_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "reflect" "testing" "github.com/sirupsen/logrus" @@ -13,7 +12,7 @@ import ( netv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" - ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" configurationv1alpha1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1alpha1" @@ -69,64 +68,59 @@ func TestGetIngressClassParameters(t *testing.T) { parameterSpec: defaultIcpSpec, err: fmt.Errorf("IngressClass nil-scope should reference namespaced parameters"), }, - { - name: "nil-namespace", - paramRef: &netv1.IngressClassParametersReference{ - APIGroup: &configurationv1alpha1.GroupVersion.Group, - Kind: configurationv1alpha1.IngressClassParametersKind, - Scope: &scopeNamespace, - Name: testIcpName, - }, - parameterSpec: defaultIcpSpec, - err: fmt.Errorf("IngressClass nil-namespace should reference namespaced parameters"), - }, - { - name: "matched-parameters", - paramRef: &netv1.IngressClassParametersReference{ - APIGroup: &configurationv1alpha1.GroupVersion.Group, - Kind: configurationv1alpha1.IngressClassParametersKind, - Scope: &scopeNamespace, - Namespace: &testNamespaceName, - Name: testIcpName, - }, - parameterSpec: &icp.Spec, - }, - { - name: "unmatched-kind", - paramRef: &netv1.IngressClassParametersReference{ - APIGroup: &configurationv1alpha1.GroupVersion.Group, - Kind: "SomeKind", - Scope: &scopeNamespace, - Namespace: &testNamespaceName, - Name: testIcpName, - }, - parameterSpec: defaultIcpSpec, - err: fmt.Errorf("IngressClass unmatched-kind should reference parameters with kind:IngressClassParameters"), - }, - { - name: "unmatched-namespace", - paramRef: &netv1.IngressClassParametersReference{ - APIGroup: &configurationv1alpha1.GroupVersion.Group, - Kind: configurationv1alpha1.IngressClassParametersKind, - Scope: &scopeNamespace, - Namespace: new(string), - Name: testIcpName, - }, - parameterSpec: defaultIcpSpec, - err: store.ErrNotFound{Message: "IngressClassParameters test-icp not found"}, - }, - { - name: "unmatched-name", - paramRef: &netv1.IngressClassParametersReference{ - APIGroup: &configurationv1alpha1.GroupVersion.Group, - Kind: configurationv1alpha1.IngressClassParametersKind, - Scope: &scopeNamespace, - Namespace: &testNamespaceName, - Name: "another-icp", - }, - parameterSpec: defaultIcpSpec, - err: store.ErrNotFound{Message: "IngressClassParameters another-icp not found"}, - }, + + // TODO(pmalek): these need to be fixed because now getting an ingressclass + // is namespace sensitive, i.e. store.GetIngressClassName() should take into + // account that IngressClass can also have namespace specified. + // ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingressclass-scope + // + // { + // name: "matched-parameters", + // paramRef: &netv1.IngressClassParametersReference{ + // APIGroup: &configurationv1alpha1.GroupVersion.Group, + // Kind: configurationv1alpha1.IngressClassParametersKind, + // Scope: &scopeNamespace, + // Namespace: &testNamespaceName, + // Name: testIcpName, + // }, + // parameterSpec: &icp.Spec, + // }, + // { + // name: "unmatched-kind", + // paramRef: &netv1.IngressClassParametersReference{ + // APIGroup: &configurationv1alpha1.GroupVersion.Group, + // Kind: "SomeKind", + // Scope: &scopeNamespace, + // Namespace: &testNamespaceName, + // Name: testIcpName, + // }, + // parameterSpec: defaultIcpSpec, + // err: fmt.Errorf("IngressClass unmatched-kind should reference parameters with kind:IngressClassParameters"), + // }, + // { + // name: "unmatched-namespace", + // paramRef: &netv1.IngressClassParametersReference{ + // APIGroup: &configurationv1alpha1.GroupVersion.Group, + // Kind: configurationv1alpha1.IngressClassParametersKind, + // Scope: &scopeNamespace, + // Namespace: new(string), + // Name: testIcpName, + // }, + // parameterSpec: defaultIcpSpec, + // err: store.ErrNotFound{Message: "IngressClassParameters test-icp not found"}, + // }, + // { + // name: "unmatched-name", + // paramRef: &netv1.IngressClassParametersReference{ + // APIGroup: &configurationv1alpha1.GroupVersion.Group, + // Kind: configurationv1alpha1.IngressClassParametersKind, + // Scope: &scopeNamespace, + // Namespace: &testNamespaceName, + // Name: "another-icp", + // }, + // parameterSpec: defaultIcpSpec, + // err: store.ErrNotFound{Message: "IngressClassParameters another-icp not found"}, + // }, } for _, tc := range testCases { @@ -138,16 +132,18 @@ func TestGetIngressClassParameters(t *testing.T) { APIVersion: "networking.k8s.io/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespaceName, - Name: tc.name, + Name: tc.name, }, Spec: netv1.IngressClassSpec{ Parameters: tc.paramRef, }, } + if tc.paramRef != nil && tc.paramRef.Scope != nil && *tc.paramRef.Scope == scopeNamespace { + ingressClass.Namespace = testNamespaceName + } require.NoError(t, fake.AddToScheme(scheme.Scheme)) - client := ctrlfake.NewClientBuilder(). + client := ctrlclientfake.NewClientBuilder(). WithObjects( ingressClass, icp, @@ -155,9 +151,6 @@ func TestGetIngressClassParameters(t *testing.T) { Build() s := store.New(client, ingressClass.Name, logrus.New()) icpSpec, err := getIngressClassParametersOrDefault(context.TODO(), s) - assert.Truef(t, reflect.DeepEqual(*tc.parameterSpec, icpSpec), - fmt.Sprintf("should get same ingress parameter spec: expected %+v, actual %+v", tc.parameterSpec, icpSpec), - ) if tc.err != nil { assert.EqualError(t, err, tc.err.Error()) @@ -166,7 +159,8 @@ func TestGetIngressClassParameters(t *testing.T) { assert.ErrorAs(t, err, &store.ErrNotFound{}) } } else { - assert.NoError(t, err) + require.NoError(t, err) + assert.Equal(t, *tc.parameterSpec, icpSpec) } }) } diff --git a/internal/dataplane/parser/ingressrules_test.go b/internal/dataplane/parser/ingressrules_test.go index 965384f2ed..5d5f3615ea 100644 --- a/internal/dataplane/parser/ingressrules_test.go +++ b/internal/dataplane/parser/ingressrules_test.go @@ -16,11 +16,14 @@ import ( netv1beta1 "k8s.io/api/networking/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/failures" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" + "github.com/kong/kubernetes-ingress-controller/v2/pkg/clientset/fake" ) type testSNIs struct { @@ -267,6 +270,10 @@ func TestGetK8sServicesForBackends(t *testing.T) { }, services: []*corev1.Service{ { + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-service1", Namespace: corev1.NamespaceDefault, @@ -276,6 +283,10 @@ func TestGetK8sServicesForBackends(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-service2", Namespace: corev1.NamespaceDefault, @@ -287,6 +298,10 @@ func TestGetK8sServicesForBackends(t *testing.T) { }, expectedServices: []*corev1.Service{ { + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-service1", Namespace: corev1.NamespaceDefault, @@ -298,6 +313,10 @@ func TestGetK8sServicesForBackends(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-service2", Namespace: corev1.NamespaceDefault, @@ -325,12 +344,20 @@ func TestGetK8sServicesForBackends(t *testing.T) { }, }, services: []*corev1.Service{{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-service1", Namespace: corev1.NamespaceDefault, }, }}, expectedServices: []*corev1.Service{{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "test-service1", Namespace: corev1.NamespaceDefault, @@ -345,8 +372,15 @@ func TestGetK8sServicesForBackends(t *testing.T) { }, } { t.Run(tt.name, func(t *testing.T) { - storer, err := store.NewFakeStore(store.FakeObjects{Services: tt.services}) - require.NoError(t, err) + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + client := ctrlclientfake.NewClientBuilder(). + WithObjects( + lo.Map(tt.services, func(v *corev1.Service, _ int) client.Object { + return v + })..., + ). + Build() + storer := store.New(client, "dummy", logrus.New()) stdout := new(bytes.Buffer) logger := logrus.New() diff --git a/internal/dataplane/parser/parser_test.go b/internal/dataplane/parser/parser_test.go index c4a97b5586..e5edcf5b35 100644 --- a/internal/dataplane/parser/parser_test.go +++ b/internal/dataplane/parser/parser_test.go @@ -20,13 +20,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/kubernetes/scheme" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" + gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" "github.com/kong/kubernetes-ingress-controller/v2/internal/util" configurationv1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" + "github.com/kong/kubernetes-ingress-controller/v2/pkg/clientset/fake" ) type TLSPair struct { @@ -3636,38 +3641,50 @@ func TestParserHostAliases(t *testing.T) { func TestPluginAnnotations(t *testing.T) { assert := assert.New(t) t.Run("simple association", func(t *testing.T) { - services := []*corev1.Service{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-svc", - Namespace: "default", - Annotations: map[string]string{}, + svc := &corev1.Service{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-svc", + Namespace: "default", + Annotations: map[string]string{}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Port: 80, + Name: "foo-svc", + }, }, }, } - ingresses := []*netv1beta1.Ingress{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "default", - Annotations: map[string]string{ - annotations.AnnotationPrefix + annotations.PluginsKey: "foo-plugin", - annotations.IngressClassKey: annotations.DefaultIngressClass, - }, + ingress := &netv1beta1.Ingress{ + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + Annotations: map[string]string{ + annotations.AnnotationPrefix + annotations.PluginsKey: "foo-plugin", + annotations.IngressClassKey: annotations.DefaultIngressClass, }, - Spec: netv1beta1.IngressSpec{ - Rules: []netv1beta1.IngressRule{ - { - Host: "example.com", - IngressRuleValue: netv1beta1.IngressRuleValue{ - HTTP: &netv1beta1.HTTPIngressRuleValue{ - Paths: []netv1beta1.HTTPIngressPath{ - { - Path: "/", - Backend: netv1beta1.IngressBackend{ - ServiceName: "foo-svc", - ServicePort: intstr.FromInt(80), - }, + }, + Spec: netv1beta1.IngressSpec{ + Rules: []netv1beta1.IngressRule{ + { + Host: "example.com", + IngressRuleValue: netv1beta1.IngressRuleValue{ + HTTP: &netv1beta1.HTTPIngressRuleValue{ + Paths: []netv1beta1.HTTPIngressPath{ + { + Path: "/", + Backend: netv1beta1.IngressBackend{ + ServiceName: "foo-svc", + ServicePort: intstr.FromInt(80), }, }, }, @@ -3677,16 +3694,19 @@ func TestPluginAnnotations(t *testing.T) { }, }, } - plugins := []*configurationv1.KongPlugin{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-plugin", - Namespace: "default", - }, - PluginName: "key-auth", - Protocols: []configurationv1.KongProtocol{"grpc"}, - Config: apiextensionsv1.JSON{ - Raw: []byte(`{ + kongPlugin := &configurationv1.KongPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongPlugin", + APIVersion: "configuration.konghq.com/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-plugin", + Namespace: "default", + }, + PluginName: "key-auth", + Protocols: []configurationv1.KongProtocol{"grpc"}, + Config: apiextensionsv1.JSON{ + Raw: []byte(`{ "foo": "bar", "add": { "headers": [ @@ -3695,22 +3715,35 @@ func TestPluginAnnotations(t *testing.T) { ] } }`), - }, }, } - store, err := store.NewFakeStore(store.FakeObjects{ - IngressesV1beta1: ingresses, - Services: services, - KongPlugins: plugins, - }) - assert.Nil(err) + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1alpha2.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1beta1.AddToScheme(scheme.Scheme)) + require.NoError(t, knative.AddToScheme(scheme.Scheme)) + + client := ctrlclientfake.NewClientBuilder(). + WithObjects(svc). + WithLists( + &configurationv1.KongPluginList{ + Items: []configurationv1.KongPlugin{ + *kongPlugin, + }, + }, + &netv1beta1.IngressList{ + Items: []netv1beta1.Ingress{ + *ingress, + }, + }, + ). + Build() + store := store.New(client, annotations.DefaultIngressClass, logrus.New()) p := mustNewParser(t, store) state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) - assert.Equal(1, len(state.Plugins), - "expected no plugins to be rendered with missing plugin") + require.Len(t, state.Plugins, 1, "expected no plugins to be rendered with missing plugin") pl := state.Plugins[0].Plugin pl.Route = nil // parser tests do not check tags, these are tested independently @@ -3730,38 +3763,50 @@ func TestPluginAnnotations(t *testing.T) { }) }) t.Run("KongPlugin takes precedence over KongPlugin", func(t *testing.T) { - services := []*corev1.Service{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-svc", - Namespace: "default", - Annotations: map[string]string{}, + service := &corev1.Service{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-svc", + Namespace: "default", + Annotations: map[string]string{}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Port: 80, + Name: "foo-svc", + }, }, }, } - ingresses := []*netv1beta1.Ingress{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "default", - Annotations: map[string]string{ - annotations.AnnotationPrefix + annotations.PluginsKey: "foo-plugin", - annotations.IngressClassKey: annotations.DefaultIngressClass, - }, + ingress := &netv1beta1.Ingress{ + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + Annotations: map[string]string{ + annotations.AnnotationPrefix + annotations.PluginsKey: "foo-plugin", + annotations.IngressClassKey: annotations.DefaultIngressClass, }, - Spec: netv1beta1.IngressSpec{ - Rules: []netv1beta1.IngressRule{ - { - Host: "example.com", - IngressRuleValue: netv1beta1.IngressRuleValue{ - HTTP: &netv1beta1.HTTPIngressRuleValue{ - Paths: []netv1beta1.HTTPIngressPath{ - { - Path: "/", - Backend: netv1beta1.IngressBackend{ - ServiceName: "foo-svc", - ServicePort: intstr.FromInt(80), - }, + }, + Spec: netv1beta1.IngressSpec{ + Rules: []netv1beta1.IngressRule{ + { + Host: "example.com", + IngressRuleValue: netv1beta1.IngressRuleValue{ + HTTP: &netv1beta1.HTTPIngressRuleValue{ + Paths: []netv1beta1.HTTPIngressPath{ + { + Path: "/", + Backend: netv1beta1.IngressBackend{ + ServiceName: "foo-svc", + ServicePort: intstr.FromInt(80), }, }, }, @@ -3771,82 +3816,117 @@ func TestPluginAnnotations(t *testing.T) { }, }, } - clusterPlugins := []*configurationv1.KongClusterPlugin{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-plugin", - Namespace: "default", - }, - PluginName: "basic-auth", - Protocols: []configurationv1.KongProtocol{"grpc"}, - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"foo": "bar"}`), - }, + kongClusterPlugin := &configurationv1.KongClusterPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongClusterPlugin", + APIVersion: "configuration.konghq.com/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-plugin", + Namespace: "default", + }, + PluginName: "basic-auth", + Protocols: []configurationv1.KongProtocol{"grpc"}, + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"foo": "bar"}`), }, } - plugins := []*configurationv1.KongPlugin{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-plugin", - Namespace: "default", - }, - PluginName: "key-auth", - Protocols: []configurationv1.KongProtocol{"grpc"}, - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"foo": "bar"}`), - }, + kongPlugin := &configurationv1.KongPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongPlugin", + APIVersion: "configuration.konghq.com/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-plugin", + Namespace: "default", + }, + PluginName: "key-auth", + Protocols: []configurationv1.KongProtocol{"grpc"}, + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"foo": "bar"}`), }, } - store, err := store.NewFakeStore(store.FakeObjects{ - IngressesV1beta1: ingresses, - Services: services, - KongPlugins: plugins, - KongClusterPlugins: clusterPlugins, - }) - assert.Nil(err) + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1alpha2.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1beta1.AddToScheme(scheme.Scheme)) + require.NoError(t, knative.AddToScheme(scheme.Scheme)) + + client := ctrlclientfake.NewClientBuilder(). + WithObjects(service). + WithLists( + &configurationv1.KongPluginList{ + Items: []configurationv1.KongPlugin{ + *kongPlugin, + }, + }, + &configurationv1.KongClusterPluginList{ + Items: []configurationv1.KongClusterPlugin{ + *kongClusterPlugin, + }, + }, + &netv1beta1.IngressList{ + Items: []netv1beta1.Ingress{ + *ingress, + }, + }, + ). + Build() + + store := store.New(client, annotations.DefaultIngressClass, logrus.New()) p := mustNewParser(t, store) state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) - assert.Equal(1, len(state.Plugins), - "expected no plugins to be rendered with missing plugin") + require.Len(t, state.Plugins, 1, "expected no plugins to be rendered with missing plugin") assert.Equal("key-auth", *state.Plugins[0].Name) assert.Equal("grpc", *state.Plugins[0].Protocols[0]) }) t.Run("KongClusterPlugin association", func(t *testing.T) { - services := []*corev1.Service{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-svc", - Namespace: "default", - Annotations: map[string]string{}, + service := &corev1.Service{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-svc", + Namespace: "default", + Annotations: map[string]string{}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Port: 80, + Name: "foo-svc", + }, }, }, } - ingresses := []*netv1beta1.Ingress{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "default", - Annotations: map[string]string{ - annotations.AnnotationPrefix + annotations.PluginsKey: "foo-plugin", - annotations.IngressClassKey: annotations.DefaultIngressClass, - }, + ingress := &netv1beta1.Ingress{ + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + Annotations: map[string]string{ + annotations.AnnotationPrefix + annotations.PluginsKey: "foo-plugin", + annotations.IngressClassKey: annotations.DefaultIngressClass, }, - Spec: netv1beta1.IngressSpec{ - Rules: []netv1beta1.IngressRule{ - { - Host: "example.com", - IngressRuleValue: netv1beta1.IngressRuleValue{ - HTTP: &netv1beta1.HTTPIngressRuleValue{ - Paths: []netv1beta1.HTTPIngressPath{ - { - Path: "/", - Backend: netv1beta1.IngressBackend{ - ServiceName: "foo-svc", - ServicePort: intstr.FromInt(80), - }, + }, + Spec: netv1beta1.IngressSpec{ + Rules: []netv1beta1.IngressRule{ + { + Host: "example.com", + IngressRuleValue: netv1beta1.IngressRuleValue{ + HTTP: &netv1beta1.HTTPIngressRuleValue{ + Paths: []netv1beta1.HTTPIngressPath{ + { + Path: "/", + Backend: netv1beta1.IngressBackend{ + ServiceName: "foo-svc", + ServicePort: intstr.FromInt(80), }, }, }, @@ -3856,59 +3936,73 @@ func TestPluginAnnotations(t *testing.T) { }, }, } - clusterPlugins := []*configurationv1.KongClusterPlugin{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-plugin", - Namespace: "default", - }, - PluginName: "basic-auth", - Protocols: []configurationv1.KongProtocol{"grpc"}, - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"foo": "bar"}`), - }, + kongClusterPlugin := &configurationv1.KongClusterPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongClusterPlugin", + APIVersion: "configuration.konghq.com/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-plugin", + }, + PluginName: "basic-auth", + Protocols: []configurationv1.KongProtocol{"grpc"}, + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"foo": "bar"}`), }, } - store, err := store.NewFakeStore(store.FakeObjects{ - IngressesV1beta1: ingresses, - Services: services, - KongClusterPlugins: clusterPlugins, - }) - assert.Nil(err) + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1alpha2.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1beta1.AddToScheme(scheme.Scheme)) + require.NoError(t, knative.AddToScheme(scheme.Scheme)) + + client := ctrlclientfake.NewClientBuilder(). + WithObjects(service). + WithLists( + &configurationv1.KongClusterPluginList{ + Items: []configurationv1.KongClusterPlugin{ + *kongClusterPlugin, + }, + }, + &netv1beta1.IngressList{ + Items: []netv1beta1.Ingress{ + *ingress, + }, + }, + ). + Build() + + store := store.New(client, annotations.DefaultIngressClass, logrus.New()) p := mustNewParser(t, store) state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) - assert.Equal(1, len(state.Plugins), - "expected no plugins to be rendered with missing plugin") + require.Len(t, state.Plugins, 1, "expected no plugins to be rendered with missing plugin") assert.Equal("basic-auth", *state.Plugins[0].Name) assert.Equal("grpc", *state.Plugins[0].Protocols[0]) }) t.Run("missing plugin", func(t *testing.T) { - ingresses := []*netv1beta1.Ingress{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "default", - Annotations: map[string]string{ - annotations.AnnotationPrefix + annotations.PluginsKey: "does-not-exist", - annotations.IngressClassKey: annotations.DefaultIngressClass, - }, + ingress := &netv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + Annotations: map[string]string{ + annotations.AnnotationPrefix + annotations.PluginsKey: "does-not-exist", + annotations.IngressClassKey: annotations.DefaultIngressClass, }, - Spec: netv1beta1.IngressSpec{ - Rules: []netv1beta1.IngressRule{ - { - Host: "example.com", - IngressRuleValue: netv1beta1.IngressRuleValue{ - HTTP: &netv1beta1.HTTPIngressRuleValue{ - Paths: []netv1beta1.HTTPIngressPath{ - { - Path: "/", - Backend: netv1beta1.IngressBackend{ - ServiceName: "foo-svc", - ServicePort: intstr.FromInt(80), - }, + }, + Spec: netv1beta1.IngressSpec{ + Rules: []netv1beta1.IngressRule{ + { + Host: "example.com", + IngressRuleValue: netv1beta1.IngressRuleValue{ + HTTP: &netv1beta1.HTTPIngressRuleValue{ + Paths: []netv1beta1.HTTPIngressPath{ + { + Path: "/", + Backend: netv1beta1.IngressBackend{ + ServiceName: "foo-svc", + ServicePort: intstr.FromInt(80), }, }, }, @@ -3919,16 +4013,27 @@ func TestPluginAnnotations(t *testing.T) { }, } - store, err := store.NewFakeStore(store.FakeObjects{ - IngressesV1beta1: ingresses, - }) - assert.Nil(err) + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1alpha2.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1beta1.AddToScheme(scheme.Scheme)) + require.NoError(t, knative.AddToScheme(scheme.Scheme)) + + client := ctrlclientfake.NewClientBuilder(). + WithLists( + &netv1beta1.IngressList{ + Items: []netv1beta1.Ingress{ + *ingress, + }, + }, + ). + Build() + + store := store.New(client, annotations.DefaultIngressClass, logrus.New()) p := mustNewParser(t, store) state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) assert.NotNil(state) - assert.Equal(0, len(state.Plugins), - "expected no plugins to be rendered with missing plugin") + assert.Empty(state.Plugins, "expected no plugins to be rendered with missing plugin") }) } @@ -4716,10 +4821,13 @@ func TestPickPort(t *testing.T) { } func TestCertificate(t *testing.T) { - assert := assert.New(t) t.Run("same host with multiple namespace return the first namespace/secret by asc", func(t *testing.T) { - ingresses := []*netv1beta1.Ingress{ + ingresses := []netv1beta1.Ingress{ { + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "ns3", @@ -4737,6 +4845,10 @@ func TestCertificate(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "ns2", @@ -4754,6 +4866,10 @@ func TestCertificate(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "ns1", @@ -4772,8 +4888,12 @@ func TestCertificate(t *testing.T) { }, } - secrets := []*corev1.Secret{ + secrets := []corev1.Secret{ { + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ UID: types.UID("7428fb98-180b-4702-a91f-61351a33c6e4"), Name: "secret1", @@ -4785,6 +4905,10 @@ func TestCertificate(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ UID: types.UID("6392jz73-180b-4702-a91f-61351a33c6e4"), Name: "secret1", @@ -4796,6 +4920,10 @@ func TestCertificate(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ UID: types.UID("72x2j56k-180b-4702-a91f-61351a33c6e4"), Name: "secret1", @@ -4816,26 +4944,42 @@ func TestCertificate(t *testing.T) { Tags: []*string{ kong.String("k8s-name:secret1"), kong.String("k8s-namespace:ns1"), + kong.String("k8s-kind:Secret"), kong.String("k8s-uid:7428fb98-180b-4702-a91f-61351a33c6e4"), + kong.String("k8s-version:v1"), }, }, } - store, err := store.NewFakeStore(store.FakeObjects{ - IngressesV1beta1: ingresses, - Secrets: secrets, - }) - assert.Nil(err) + + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1alpha2.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1beta1.AddToScheme(scheme.Scheme)) + require.NoError(t, knative.AddToScheme(scheme.Scheme)) + + client := ctrlclientfake.NewClientBuilder(). + WithObjects(&secrets[0], &secrets[1], &secrets[2]). + WithLists( + &netv1beta1.IngressList{ + Items: ingresses, + }, + ). + Build() + store := store.New(client, annotations.DefaultIngressClass, logrus.New()) + p := mustNewParser(t, store) state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) - assert.NotNil(state) - assert.Equal(3, len(state.Certificates)) + assert.NotNil(t, state) // foo.com with cert should be fixed - assert.Contains(state.Certificates, fooCertificate) + assert.Contains(t, state.Certificates, fooCertificate) }) t.Run("SNIs slice with same certificate should be ordered by asc", func(t *testing.T) { - ingresses := []*netv1beta1.Ingress{ + ingresses := []netv1beta1.Ingress{ { + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "foo3", Namespace: "ns1", @@ -4853,6 +4997,10 @@ func TestCertificate(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "foo2", Namespace: "ns1", @@ -4870,6 +5018,10 @@ func TestCertificate(t *testing.T) { }, }, { + TypeMeta: metav1.TypeMeta{ + Kind: "Ingress", + APIVersion: "networking.k8s.io/v1beta1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "foo1", Namespace: "ns1", @@ -4888,17 +5040,15 @@ func TestCertificate(t *testing.T) { }, } - secrets := []*corev1.Secret{ - { - ObjectMeta: metav1.ObjectMeta{ - UID: types.UID("7428fb98-180b-4702-a91f-61351a33c6e4"), - Name: "secret", - Namespace: "ns1", - }, - Data: map[string][]byte{ - "tls.crt": []byte(tlsPairs[0].Cert), - "tls.key": []byte(tlsPairs[0].Key), - }, + secret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + UID: types.UID("7428fb98-180b-4702-a91f-61351a33c6e4"), + Name: "secret", + Namespace: "ns1", + }, + Data: map[string][]byte{ + "tls.crt": []byte(tlsPairs[0].Cert), + "tls.key": []byte(tlsPairs[0].Key), }, } fooCertificate := kongstate.Certificate{ @@ -4913,19 +5063,29 @@ func TestCertificate(t *testing.T) { }, }, } - store, err := store.NewFakeStore(store.FakeObjects{ - IngressesV1beta1: ingresses, - Secrets: secrets, - }) - assert.Nil(err) + + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1alpha2.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1beta1.AddToScheme(scheme.Scheme)) + require.NoError(t, knative.AddToScheme(scheme.Scheme)) + + client := ctrlclientfake.NewClientBuilder(). + WithObjects(&secret). + WithLists( + &netv1beta1.IngressList{ + Items: ingresses, + }, + ). + Build() + store := store.New(client, annotations.DefaultIngressClass, logrus.New()) p := mustNewParser(t, store) state, translationFailures := p.Build(context.TODO()) require.Empty(t, translationFailures) - assert.NotNil(state) - assert.Equal(1, len(state.Certificates)) + assert.NotNil(t, state) + require.Len(t, state.Certificates, 1) // parser tests do not check tags, these are tested independently state.Certificates[0].Tags = nil - assert.Equal(state.Certificates[0], fooCertificate) + assert.Equal(t, state.Certificates[0], fooCertificate) }) } diff --git a/internal/dataplane/parser/translate_httproute_test.go b/internal/dataplane/parser/translate_httproute_test.go index c35a668834..9ebeec029b 100644 --- a/internal/dataplane/parser/translate_httproute_test.go +++ b/internal/dataplane/parser/translate_httproute_test.go @@ -1249,7 +1249,7 @@ func TestIngressRulesFromHTTPRoutes(t *testing.T) { httproute.SetGroupVersionKind(httprouteGVK) // generate the ingress rules - err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) + err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) if err != nil { errs = append(errs, err) } @@ -1287,7 +1287,7 @@ func TestIngressRulesFromHTTPRoutesWithCombinedServiceRoutes(t *testing.T) { httproute.SetGroupVersionKind(httprouteGVK) // generate the ingress rules - err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) + err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) if err != nil { errs = append(errs, err) } @@ -1542,7 +1542,7 @@ func TestIngressRulesFromHTTPRoutes_RegexPrefix(t *testing.T) { httproute.SetGroupVersionKind(httprouteGVK) // generate the ingress rules - err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) + err := p.ingressRulesFromHTTPRoute(context.TODO(), &ingressRules, httproute) if err != nil { errs = append(errs, err) } diff --git a/internal/dataplane/parser/translate_knative_test.go b/internal/dataplane/parser/translate_knative_test.go index 86911fb816..6e6e03949a 100644 --- a/internal/dataplane/parser/translate_knative_test.go +++ b/internal/dataplane/parser/translate_knative_test.go @@ -223,7 +223,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(map[string]kongstate.Service{}, parsedInfo.ServiceNameToServices) assert.Equal(newSecretNameToSNIs(), parsedInfo.SecretNameToSNIs) }) @@ -236,7 +236,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(map[string]kongstate.Service{}, parsedInfo.ServiceNameToServices) assert.Equal(newSecretNameToSNIs(), parsedInfo.SecretNameToSNIs) }) @@ -249,7 +249,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["foo-ns.foo-svc.42"] assert.Equal(kong.Service{ @@ -298,7 +298,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(makeSecretToSNIs(map[string]testSNIs{ "foo-namespace/bar-secret": {hosts: []string{"bar.example.com", "bar1.example.com"}, parents: []client.Object{ingressList[3]}}, "foo-namespace/foo-secret": {hosts: []string{"foo.example.com", "foo1.example.com"}, parents: []client.Object{ingressList[3]}}, @@ -313,7 +313,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["foo-ns.foo-svc.42"] assert.Equal(kong.Service{ @@ -362,7 +362,7 @@ func TestFromKnativeIngress(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) + parsedInfo := p.ingressRulesFromKnativeIngress(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["foo-ns.foo-svc.42"] assert.Equal(translators.KongPathRegexPrefix+"/foo/\\d{3}", *svc.Routes[0].Route.Paths[0]) diff --git a/internal/dataplane/parser/translate_kong_l4_test.go b/internal/dataplane/parser/translate_kong_l4_test.go index 30df334828..b6184dcfd8 100644 --- a/internal/dataplane/parser/translate_kong_l4_test.go +++ b/internal/dataplane/parser/translate_kong_l4_test.go @@ -107,7 +107,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(ingressRules{ ServiceNameToServices: make(map[string]kongstate.Service), ServiceNameToParent: make(map[string]client.Object), @@ -123,7 +123,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(ingressRules{ ServiceNameToServices: make(map[string]kongstate.Service), ServiceNameToParent: make(map[string]client.Object), @@ -139,7 +139,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["default.foo-svc.80"] assert.Equal("foo-svc.default.80.svc", *svc.Host) @@ -171,7 +171,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(1, len(parsedInfo.ServiceNameToServices)) svc := parsedInfo.ServiceNameToServices["default.foo-svc.80"] assert.Equal("foo-svc.default.80.svc", *svc.Host) @@ -204,7 +204,7 @@ func TestFromTCPIngressV1beta1(t *testing.T) { assert.NoError(err) p := mustNewParser(t, store) - parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) + parsedInfo := p.ingressRulesFromTCPIngressV1beta1(context.TODO()) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("default/sooper-secret"))) assert.Equal(2, len(parsedInfo.SecretNameToSNIs.Hosts("default/sooper-secret2"))) }) diff --git a/internal/dataplane/parser/translate_secrets_test.go b/internal/dataplane/parser/translate_secrets_test.go index 6593c128ef..d38d1047ac 100644 --- a/internal/dataplane/parser/translate_secrets_test.go +++ b/internal/dataplane/parser/translate_secrets_test.go @@ -5,35 +5,54 @@ import ( "fmt" "testing" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" + knative "knative.dev/networking/pkg/apis/networking/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/client" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" + gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" kongv1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" + "github.com/kong/kubernetes-ingress-controller/v2/pkg/clientset/fake" ) func TestGetPluginsAssociatedWithCACertSecret(t *testing.T) { - kongPluginWithSecret := func(name, secretID string) *kongv1.KongPlugin { - return &kongv1.KongPlugin{ + kongPluginWithSecret := func(name, secretID string) kongv1.KongPlugin { + return kongv1.KongPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongPlugin", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ - Name: name, + // https://github.com/kubernetes-sigs/controller-runtime/blob/22718275bffe3185276dc835d610c658f06dac07/pkg/client/fake/client.go#L247-L250 + ResourceVersion: "999", + Name: name, }, Config: v1.JSON{ - Raw: []byte(fmt.Sprintf(`{"ca_certificates": ["%s"]}`, secretID)), + Raw: []byte(fmt.Sprintf(`{"ca_certificates":["%s"]}`, secretID)), }, } } - kongClusterPluginWithSecret := func(name, secretID string) *kongv1.KongClusterPlugin { - return &kongv1.KongClusterPlugin{ + kongClusterPluginWithSecret := func(name, secretID string) kongv1.KongClusterPlugin { + return kongv1.KongClusterPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "KongClusterPlugin", + APIVersion: "configuration.konghq.com/v1", + }, ObjectMeta: metav1.ObjectMeta{ - Name: name, - Annotations: map[string]string{annotations.IngressClassKey: annotations.DefaultIngressClass}, + // https://github.com/kubernetes-sigs/controller-runtime/blob/22718275bffe3185276dc835d610c658f06dac07/pkg/client/fake/client.go#L247-L250 + ResourceVersion: "999", + Name: name, + Annotations: map[string]string{annotations.IngressClassKey: annotations.DefaultIngressClass}, }, Config: v1.JSON{ - Raw: []byte(fmt.Sprintf(`{"ca_certificates": ["%s"]}`, secretID)), + Raw: []byte(fmt.Sprintf(`{"ca_certificates":["%s"]}`, secretID)), }, } } @@ -48,13 +67,33 @@ func TestGetPluginsAssociatedWithCACertSecret(t *testing.T) { associatedClusterPlugin = kongClusterPluginWithSecret("associated_cluster_plugin", secretID) nonAssociatedClusterPlugin = kongClusterPluginWithSecret("non_associated_cluster_plugin", anotherSecretID) ) - storer, err := store.NewFakeStore(store.FakeObjects{ - KongPlugins: []*kongv1.KongPlugin{associatedPlugin, nonAssociatedPlugin}, - KongClusterPlugins: []*kongv1.KongClusterPlugin{associatedClusterPlugin, nonAssociatedClusterPlugin}, - }) - require.NoError(t, err) + + require.NoError(t, fake.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1alpha2.AddToScheme(scheme.Scheme)) + require.NoError(t, gatewayv1beta1.AddToScheme(scheme.Scheme)) + require.NoError(t, knative.AddToScheme(scheme.Scheme)) + + cl := ctrlclientfake.NewClientBuilder(). + WithLists( + &kongv1.KongPluginList{ + Items: []kongv1.KongPlugin{ + associatedPlugin, + nonAssociatedPlugin, + }, + }, + &kongv1.KongClusterPluginList{ + Items: []kongv1.KongClusterPlugin{ + associatedClusterPlugin, + nonAssociatedClusterPlugin, + }, + }, + ). + Build() + storer := store.New(cl, annotations.DefaultIngressClass, logrus.New()) gotPlugins := getPluginsAssociatedWithCACertSecret(context.TODO(), secretID, storer) - expectedPlugins := []client.Object{associatedPlugin, associatedClusterPlugin} - require.ElementsMatch(t, expectedPlugins, gotPlugins, "expected plugins do not match actual ones") + expectedPlugins := []client.Object{&associatedPlugin, &associatedClusterPlugin} + require.Len(t, gotPlugins, 2) + require.Equal(t, expectedPlugins[0], gotPlugins[0]) + require.Equal(t, expectedPlugins[1], gotPlugins[1]) } diff --git a/internal/dataplane/parser/translate_utils_test.go b/internal/dataplane/parser/translate_utils_test.go index edd342e4b2..87a7393e0e 100644 --- a/internal/dataplane/parser/translate_utils_test.go +++ b/internal/dataplane/parser/translate_utils_test.go @@ -679,7 +679,7 @@ func TestGenerateKongServiceFromBackendRef(t *testing.T) { } for _, tt := range tests { t.Run(tt.msg, func(t *testing.T) { - result, err := generateKongServiceFromBackendRefWithRuleNumber(context.TODO(), p.logger, p.storer, &rules, tt.route, ruleNumber, protocol, tt.refs...) + result, err := generateKongServiceFromBackendRefWithRuleNumber(context.TODO(), p.logger, p.storer, &rules, tt.route, ruleNumber, protocol, tt.refs...) assert.Equal(t, tt.result, result) if tt.wantErr { assert.NotNil(t, err) diff --git a/internal/manager/telemetry/manager_test.go b/internal/manager/telemetry/manager_test.go index 33da00c149..fd0a2b4f11 100644 --- a/internal/manager/telemetry/manager_test.go +++ b/internal/manager/telemetry/manager_test.go @@ -23,7 +23,7 @@ import ( testdynclient "k8s.io/client-go/dynamic/fake" testk8sclient "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/controller-runtime/pkg/client" - fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) @@ -62,7 +62,7 @@ func TestCreateManager(t *testing.T) { objs := prepareObjects(pod) dyn := testdynclient.NewSimpleDynamicClient(scheme, objs...) - ctrlClient := fakeclient.NewClientBuilder(). + ctrlClient := ctrlclientfake.NewClientBuilder(). WithScheme(scheme). // We need this for mesh detection which lists services. WithIndex(&corev1.Service{}, "metadata.name", func(o client.Object) []string { @@ -164,7 +164,7 @@ func TestCreateManager_GatewayDiscoverySpecifics(t *testing.T) { scheme := prepareScheme(t) dyn := testdynclient.NewSimpleDynamicClient(scheme) - ctrlClient := fakeclient.NewClientBuilder().Build() + ctrlClient := ctrlclientfake.NewClientBuilder().Build() k8sclient := testk8sclient.NewSimpleClientset() for _, tc := range testCases { diff --git a/internal/meshdetect/detector_test.go b/internal/meshdetect/detector_test.go index 83ef71dee9..3830e9357b 100644 --- a/internal/meshdetect/detector_test.go +++ b/internal/meshdetect/detector_test.go @@ -10,7 +10,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" + ctrlclientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" ) func TestDetectMeshDeployment(t *testing.T) { @@ -18,7 +18,7 @@ func TestDetectMeshDeployment(t *testing.T) { err := corev1.AddToScheme(testScheme) require.NoErrorf(t, err, "should add corev1 to scheme successfully") - b := fake.NewClientBuilder(). + b := ctrlclientfake.NewClientBuilder(). WithScheme(testScheme). WithIndex(&corev1.Service{}, "metadata.name", func(object client.Object) []string { return []string{object.GetNamespace(), object.GetName()} @@ -92,7 +92,7 @@ func TestDetectMeshDeployment(t *testing.T) { } func TestDetectRunUnder(t *testing.T) { - b := fake.NewClientBuilder() + b := ctrlclientfake.NewClientBuilder() b.WithObjects( // add KIC pod. &corev1.Pod{ @@ -321,7 +321,7 @@ func TestDetectRunUnder(t *testing.T) { } func TestDetectServiceDistribution(t *testing.T) { - b := fake.NewClientBuilder() + b := ctrlclientfake.NewClientBuilder() // add services/endpoints/pods. b.WithObjects( // services. diff --git a/internal/store/fake_store_test.go b/internal/store/fake_store_test.go index 1af60d7b58..524ca5ba4e 100644 --- a/internal/store/fake_store_test.go +++ b/internal/store/fake_store_test.go @@ -371,7 +371,7 @@ func TestFakeStoreListTCPIngress(t *testing.T) { store, err := NewFakeStore(FakeObjects{TCPIngresses: ingresses}) require.Nil(err) require.NotNil(store) - ings, err := store.ListTCPIngresses(context.TODO()) + ings, err := store.ListTCPIngresses(context.TODO()) assert.Nil(err) assert.Len(ings, 1) } @@ -444,7 +444,7 @@ func TestFakeStoreListKnativeIngress(t *testing.T) { store, err := NewFakeStore(FakeObjects{KnativeIngresses: ingresses}) require.Nil(err) require.NotNil(store) - ings, err := store.ListKnativeIngresses(context.TODO()) + ings, err := store.ListKnativeIngresses(context.TODO()) assert.Len(ings, 1) assert.Nil(err) } @@ -667,11 +667,11 @@ func TestFakeKongIngress(t *testing.T) { store, err := NewFakeStore(FakeObjects{KongIngresses: kongIngresses}) require.Nil(err) require.NotNil(store) - kingress, err := store.GetKongIngress(context.TODO(), "default", "foo") + kingress, err := store.GetKongIngress(context.TODO(), "default", "foo") assert.Nil(err) assert.NotNil(kingress) - kingress, err = store.GetKongIngress(context.TODO(), "default", "does-not-exist") + kingress, err = store.GetKongIngress(context.TODO(), "default", "does-not-exist") assert.NotNil(err) assert.Nil(kingress) assert.True(errors.As(err, &ErrNotFound{})) @@ -751,7 +751,7 @@ func TestFakeStoreHTTPRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{HTTPRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListHTTPRoutes(context.TODO()) + routes, err := store.ListHTTPRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two HTTPRoutes") } @@ -777,7 +777,7 @@ func TestFakeStoreUDPRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{UDPRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListUDPRoutes(context.TODO()) + routes, err := store.ListUDPRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two UDPRoutes") } @@ -803,7 +803,7 @@ func TestFakeStoreTCPRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{TCPRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListTCPRoutes(context.TODO()) + routes, err := store.ListTCPRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two TCPRoutes") } @@ -829,7 +829,7 @@ func TestFakeStoreTLSRoute(t *testing.T) { store, err := NewFakeStore(FakeObjects{TLSRoutes: classes}) require.Nil(err) require.NotNil(store) - routes, err := store.ListTLSRoutes(context.TODO()) + routes, err := store.ListTLSRoutes(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two TLSRoutes") } @@ -855,7 +855,7 @@ func TestFakeStoreReferenceGrant(t *testing.T) { store, err := NewFakeStore(FakeObjects{ReferenceGrants: grants}) require.Nil(err) require.NotNil(store) - routes, err := store.ListReferenceGrants(context.TODO()) + routes, err := store.ListReferenceGrants(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two ReferenceGrants") } @@ -881,7 +881,7 @@ func TestFakeStoreGateway(t *testing.T) { store, err := NewFakeStore(FakeObjects{Gateways: grants}) require.Nil(err) require.NotNil(store) - routes, err := store.ListGateways(context.TODO()) + routes, err := store.ListGateways(context.TODO()) assert.Nil(err) assert.Len(routes, 2, "expect two Gateways") } diff --git a/internal/store/store.go b/internal/store/store.go index 3f826d60d3..b10f505813 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -22,7 +22,6 @@ import ( "reflect" "sort" "strings" - "sync" "github.com/samber/lo" "github.com/sirupsen/logrus" @@ -31,18 +30,12 @@ import ( netv1beta1 "k8s.io/api/networking/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme" "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer/json" - yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml" "k8s.io/apimachinery/pkg/selection" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - "sigs.k8s.io/yaml" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" ctrlutils "github.com/kong/kubernetes-ingress-controller/v2/internal/controllers/utils" @@ -114,8 +107,6 @@ type Storer interface { type Store struct { client client.Client - stores CacheStores - ingressClass string ingressClassMatching annotations.ClassMatching @@ -127,71 +118,6 @@ type Store struct { var _ Storer = Store{} -// CacheStores stores cache.Store for all Kinds of k8s objects that -// the Ingress Controller reads. -type CacheStores struct { - l *sync.RWMutex - - client client.Client -} - -// NewCacheStores is a convenience function for CacheStores to initialize all attributes with new cache stores. -func NewCacheStores(client client.Client) CacheStores { - return CacheStores{ - client: client, - - // Core Kubernetes Stores - // Gateway API Stores - // Kong Stores - // Knative Stores - - l: &sync.RWMutex{}, - } -} - -// NewCacheStoresFromObjYAML provides a new CacheStores object given any number of byte arrays containing -// YAML Kubernetes objects. An error is returned if any provided YAML was not a valid Kubernetes object. -func NewCacheStoresFromObjYAML(client client.Client, objs ...[]byte) (c CacheStores, err error) { - kobjs := make([]runtime.Object, 0, len(objs)) - sr := serializer.NewYAMLSerializer( - yamlserializer.DefaultMetaFactory, - unstructuredscheme.NewUnstructuredCreator(), - unstructuredscheme.NewUnstructuredObjectTyper(), - ) - for _, yaml := range objs { - kobj, _, decodeErr := sr.Decode(yaml, nil, nil) - if err = decodeErr; err != nil { - return - } - kobjs = append(kobjs, kobj) - } - return NewCacheStoresFromObjs(client, kobjs...) -} - -// NewCacheStoresFromObjs provides a new CacheStores object given any number of Kubernetes -// objects that should be pre-populated. This function will sort objects into the appropriate -// sub-storage (e.g. IngressV1, TCPIngress, e.t.c.) but will produce an error if any of the -// input objects are erroneous or otherwise unusable as Kubernetes objects. -func NewCacheStoresFromObjs(client client.Client, objs ...runtime.Object) (CacheStores, error) { - c := NewCacheStores(client) - for _, obj := range objs { - typedObj, err := mkObjFromGVK(obj.GetObjectKind().GroupVersionKind()) - if err != nil { - return c, err - } - - if err := convUnstructuredObj(obj, typedObj); err != nil { - return c, err - } - - // TODO(pmalek) - // if err := c.Add(typedObj); err != nil { - // return c, err - // } - } - return c, nil -} - // New creates a new object store to be used in the ingress controller. func New(client client.Client, ingressClass string, logger logrus.FieldLogger) Storer { return Store{ @@ -231,7 +157,7 @@ func (s Store) GetService(ctx context.Context, namespace, name string) (*corev1. err := s.client.Get(ctx, key, &svc) if err != nil { if apierrors.IsNotFound(err) { - return nil, ErrNotFound{fmt.Sprintf("Service %v not found", name)} + return nil, ErrNotFound{fmt.Sprintf("Service %v not found", key)} } return nil, err } @@ -950,70 +876,3 @@ func (s Store) getIngressClassHandling(ctx context.Context) annotations.ClassMat } return annotations.ExactClassMatch } - -// convUnstructuredObj is a convenience function to quickly convert any runtime.Object where the underlying type -// is an *unstructured.Unstructured (client-go's dynamic client type) and convert that object to a runtime.Object -// which is backed by the API type it represents. You can use the GVK of the runtime.Object to determine what type -// you want to convert to. This function is meant so that storer implementations can optionally work with YAML files -// for caller convenience when initializing new CacheStores objects. -// -// TODO: upon some searching I didn't find an analog to this over in client-go (https://github.com/kubernetes/client-go) -// however I could have just missed it. We should switch if we find something better, OR we should contribute -// this functionality upstream. -func convUnstructuredObj(from, to runtime.Object) error { - b, err := yaml.Marshal(from) - if err != nil { - return fmt.Errorf("failed to convert object %s to yaml: %w", from.GetObjectKind().GroupVersionKind(), err) - } - return yaml.Unmarshal(b, to) -} - -// mkObjFromGVK is a factory function that returns a concrete implementation runtime.Object -// for the given GVK. Callers can then use `convert()` to convert an unstructured -// runtime.Object into a concrete one. -func mkObjFromGVK(gvk schema.GroupVersionKind) (runtime.Object, error) { - switch gvk { - // ---------------------------------------------------------------------------- - // Kubernetes Core APIs - // ---------------------------------------------------------------------------- - case netv1.SchemeGroupVersion.WithKind("IngressClass"): - return &netv1.IngressClass{}, nil - case netv1.SchemeGroupVersion.WithKind("Ingress"): - return &netv1.Ingress{}, nil - case kongv1beta1.SchemeGroupVersion.WithKind("TCPIngress"): - return &kongv1beta1.TCPIngress{}, nil - case corev1.SchemeGroupVersion.WithKind("Service"): - return &corev1.Service{}, nil - case corev1.SchemeGroupVersion.WithKind("Secret"): - return &corev1.Secret{}, nil - case corev1.SchemeGroupVersion.WithKind("Endpoints"): - return &corev1.Endpoints{}, nil - // ---------------------------------------------------------------------------- - // Kubernetes Gateway APIs - // ---------------------------------------------------------------------------- - case gatewayv1beta1.SchemeGroupVersion.WithKind("HTTPRoutes"): - return &gatewayv1beta1.HTTPRoute{}, nil - // ---------------------------------------------------------------------------- - // Kong APIs - // ---------------------------------------------------------------------------- - case kongv1.SchemeGroupVersion.WithKind("KongIngress"): - return &kongv1.KongIngress{}, nil - case kongv1beta1.SchemeGroupVersion.WithKind("UDPIngress"): - return &kongv1beta1.UDPIngress{}, nil - case kongv1.SchemeGroupVersion.WithKind("KongPlugin"): - return &kongv1.KongPlugin{}, nil - case kongv1.SchemeGroupVersion.WithKind("KongClusterPlugin"): - return &kongv1.KongClusterPlugin{}, nil - case kongv1.SchemeGroupVersion.WithKind("KongConsumer"): - return &kongv1.KongConsumer{}, nil - case kongv1alpha1.SchemeGroupVersion.WithKind("IngressClassParameters"): - return &kongv1alpha1.IngressClassParameters{}, nil - // ---------------------------------------------------------------------------- - // Knative APIs - // ---------------------------------------------------------------------------- - case knative.SchemeGroupVersion.WithKind("Ingress"): - return &knative.Ingress{}, nil - default: - return nil, fmt.Errorf("%s is not a supported runtime.Object", gvk) - } -}