diff --git a/go.mod b/go.mod index 871be129f3..87d2c55a9a 100644 --- a/go.mod +++ b/go.mod @@ -10,9 +10,9 @@ require ( github.com/onsi/ginkgo/v2 v2.3.1 github.com/onsi/gomega v1.22.1 github.com/spf13/pflag v1.0.5 - golang.org/x/net v0.0.0-20220722155237-a158d28d115b k8s.io/api v0.25.3 k8s.io/apimachinery v0.25.3 + k8s.io/client-go v0.25.3 sigs.k8s.io/controller-runtime v0.13.0 sigs.k8s.io/gateway-api v0.5.1 ) @@ -55,6 +55,7 @@ require ( go.uber.org/multierr v1.7.0 // indirect go.uber.org/zap v1.21.0 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect @@ -69,7 +70,6 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.25.0 // indirect - k8s.io/client-go v0.25.0 // indirect k8s.io/component-base v0.25.0 // indirect k8s.io/klog/v2 v2.70.1 // indirect k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect diff --git a/go.sum b/go.sum index 371259840d..b6746e7515 100644 --- a/go.sum +++ b/go.sum @@ -629,8 +629,8 @@ k8s.io/apiextensions-apiserver v0.25.0 h1:CJ9zlyXAbq0FIW8CD7HHyozCMBpDSiH7EdrSTC k8s.io/apiextensions-apiserver v0.25.0/go.mod h1:3pAjZiN4zw7R8aZC5gR0y3/vCkGlAjCazcg1me8iB/E= k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc= k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= -k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E= -k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8= +k8s.io/client-go v0.25.3 h1:oB4Dyl8d6UbfDHD8Bv8evKylzs3BXzzufLiO27xuPs0= +k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA= k8s.io/component-base v0.25.0 h1:haVKlLkPCFZhkcqB6WCvpVxftrg6+FK5x1ZuaIDaQ5Y= k8s.io/component-base v0.25.0/go.mod h1:F2Sumv9CnbBlqrpdf7rKZTmmd2meJq0HizeyY/yAFxk= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= diff --git a/internal/implementations/endpointslice/endpointslice.go b/internal/implementations/endpointslice/endpointslice.go deleted file mode 100644 index 497108a42f..0000000000 --- a/internal/implementations/endpointslice/endpointslice.go +++ /dev/null @@ -1,48 +0,0 @@ -package implementation - -import ( - "github.com/go-logr/logr" - discoveryV1 "k8s.io/api/discovery/v1" - "k8s.io/apimachinery/pkg/types" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" -) - -type EndpointSliceImplementation struct { - conf config.Config - eventCh chan<- interface{} -} - -// NewEndpointSliceImplementation creates a new EndpointSliceImplementation. -func NewEndpointSliceImplementation(cfg config.Config, eventCh chan<- interface{}) *EndpointSliceImplementation { - return &EndpointSliceImplementation{ - conf: cfg, - eventCh: eventCh, - } -} - -func (impl *EndpointSliceImplementation) Logger() logr.Logger { - return impl.conf.Logger -} - -func (impl *EndpointSliceImplementation) Upsert(endpSlice *discoveryV1.EndpointSlice) { - impl.Logger().Info("EndpointSlice was upserted", - "namespace", endpSlice.Namespace, "name", endpSlice.Name, - ) - - impl.eventCh <- &events.UpsertEvent{ - Resource: endpSlice, - } -} - -func (impl *EndpointSliceImplementation) Remove(nsname types.NamespacedName) { - impl.Logger().Info("EndpointSlice resource was removed", - "namespace", nsname.Namespace, "name", nsname.Name, - ) - - impl.eventCh <- &events.DeleteEvent{ - NamespacedName: nsname, - Type: &discoveryV1.EndpointSlice{}, - } -} diff --git a/internal/implementations/endpointslice/endpointslice_test.go b/internal/implementations/endpointslice/endpointslice_test.go deleted file mode 100644 index ca4899ef65..0000000000 --- a/internal/implementations/endpointslice/endpointslice_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package implementation_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - discoveryV1 "k8s.io/api/discovery/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - implementation "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/endpointslice" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -var _ = Describe("EndpointSliceImplementation", func() { - var ( - eventCh chan interface{} - impl sdk.EndpointSliceImpl - ) - - BeforeEach(func() { - eventCh = make(chan interface{}) - - impl = implementation.NewEndpointSliceImplementation(config.Config{ - Logger: zap.New(), - }, eventCh) - }) - - const endpointSliceName = "my-endpoint-slice" - const endpointSliceNamespace = "test" - - Describe("Implementation processes EndpointSlices", func() { - It("should process upsert", func() { - endpointSlice := &discoveryV1.EndpointSlice{ - ObjectMeta: metav1.ObjectMeta{ - Name: endpointSliceName, - Namespace: endpointSliceNamespace, - }, - } - - go func() { - impl.Upsert(endpointSlice) - }() - - Eventually(eventCh).Should(Receive(Equal(&events.UpsertEvent{Resource: endpointSlice}))) - }) - - It("should process remove", func() { - nsname := types.NamespacedName{Name: endpointSliceName, Namespace: endpointSliceNamespace} - - go func() { - impl.Remove(nsname) - }() - - Eventually(eventCh).Should(Receive(Equal( - &events.DeleteEvent{ - NamespacedName: nsname, - Type: &discoveryV1.EndpointSlice{}, - }))) - }) - }) -}) diff --git a/internal/implementations/endpointslice/implementation_suite_test.go b/internal/implementations/endpointslice/implementation_suite_test.go deleted file mode 100644 index 30887c0e4c..0000000000 --- a/internal/implementations/endpointslice/implementation_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package implementation_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestEndpointSliceImplementation(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Endpoint Slice Implementation Suite") -} diff --git a/internal/implementations/gateway/gateway.go b/internal/implementations/gateway/gateway.go deleted file mode 100644 index 67c4afffca..0000000000 --- a/internal/implementations/gateway/gateway.go +++ /dev/null @@ -1,49 +0,0 @@ -package implementation - -import ( - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -type gatewayImplementation struct { - logger logr.Logger - eventCh chan<- interface{} -} - -func NewGatewayImplementation(conf config.Config, eventCh chan<- interface{}) sdk.GatewayImpl { - return &gatewayImplementation{ - logger: conf.Logger, - eventCh: eventCh, - } -} - -// FIXME(pleshakov) All Implementations (Gateway, HTTPRoute, ...) look similar. Consider writing a general-purpose -// component to implement all implementations. This will avoid the duplication code and tests. - -func (impl *gatewayImplementation) Upsert(gw *v1beta1.Gateway) { - impl.logger.Info("Gateway was upserted", - "namespace", gw.Namespace, - "name", gw.Name, - ) - - impl.eventCh <- &events.UpsertEvent{ - Resource: gw, - } -} - -func (impl *gatewayImplementation) Remove(nsname types.NamespacedName) { - impl.logger.Info("Gateway was removed", - "namespace", nsname.Namespace, - "name", nsname.Name, - ) - - impl.eventCh <- &events.DeleteEvent{ - NamespacedName: nsname, - Type: &v1beta1.Gateway{}, - } -} diff --git a/internal/implementations/gateway/gateway_test.go b/internal/implementations/gateway/gateway_test.go deleted file mode 100644 index 2d68694913..0000000000 --- a/internal/implementations/gateway/gateway_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package implementation_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - implementation "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/gateway" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -var _ = Describe("GatewayImplementation", func() { - var ( - eventCh chan interface{} - impl sdk.GatewayImpl - ) - - BeforeEach(func() { - eventCh = make(chan interface{}) - - impl = implementation.NewGatewayImplementation(config.Config{ - Logger: zap.New(), - }, eventCh) - }) - - Describe("Implementation processes Gateways", func() { - It("should process upsert", func() { - gc := &v1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-add", - Name: "gateway", - }, - } - - go func() { - impl.Upsert(gc) - }() - - Eventually(eventCh).Should(Receive(Equal(&events.UpsertEvent{Resource: gc}))) - }) - - It("should process remove", func() { - nsname := types.NamespacedName{Namespace: "test-remove", Name: "gateway"} - - go func() { - impl.Remove(nsname) - }() - - Eventually(eventCh).Should(Receive(Equal( - &events.DeleteEvent{ - NamespacedName: nsname, - Type: &v1beta1.Gateway{}, - }))) - }) - }) -}) diff --git a/internal/implementations/gateway/implementation_suite_test.go b/internal/implementations/gateway/implementation_suite_test.go deleted file mode 100644 index dffdfe85a9..0000000000 --- a/internal/implementations/gateway/implementation_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package implementation_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestGatewayImplementation(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Gateway Implementation Suite") -} diff --git a/internal/implementations/gatewayclass/gatewayclass.go b/internal/implementations/gatewayclass/gatewayclass.go deleted file mode 100644 index 3bf254ba02..0000000000 --- a/internal/implementations/gatewayclass/gatewayclass.go +++ /dev/null @@ -1,64 +0,0 @@ -package implementation - -import ( - "fmt" - - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -type gatewayClassImplementation struct { - logger logr.Logger - gatewayClassName string - eventCh chan<- interface{} -} - -func NewGatewayClassImplementation(conf config.Config, eventCh chan<- interface{}) sdk.GatewayClassImpl { - return &gatewayClassImplementation{ - logger: conf.Logger, - gatewayClassName: conf.GatewayClassName, - eventCh: eventCh, - } -} - -func (impl *gatewayClassImplementation) Upsert(gc *v1beta1.GatewayClass) { - if gc.Name != impl.gatewayClassName { - msg := fmt.Sprintf("GatewayClass was upserted but ignored because this controller only supports the GatewayClass %s", impl.gatewayClassName) - impl.logger.Info(msg, - "name", gc.Name, - ) - return - } - - impl.eventCh <- &events.UpsertEvent{ - Resource: gc, - } - - impl.logger.Info("GatewayClass was upserted", - "name", gc.Name) -} - -func (impl *gatewayClassImplementation) Remove(nsname types.NamespacedName) { - // GatewayClass is a cluster scoped resource - no namespace. - - if nsname.Name != impl.gatewayClassName { - msg := fmt.Sprintf("GatewayClass was removed but ignored because this controller only supports the GatewayClass %s", impl.gatewayClassName) - impl.logger.Info(msg, - "name", nsname.Name, - ) - return - } - - impl.logger.Info("GatewayClass was removed", - "name", nsname.Name) - - impl.eventCh <- &events.DeleteEvent{ - NamespacedName: nsname, - Type: &v1beta1.GatewayClass{}, - } -} diff --git a/internal/implementations/gatewayclass/gatewayclass_test.go b/internal/implementations/gatewayclass/gatewayclass_test.go deleted file mode 100644 index 1253783968..0000000000 --- a/internal/implementations/gatewayclass/gatewayclass_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package implementation_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - implementation "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/gatewayclass" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -var _ = Describe("GatewayClassImplementation", func() { - var ( - eventCh chan interface{} - impl sdk.GatewayClassImpl - ) - - const ( - className = "my-class" - unrelatedClassName = "not-my-class" - ) - - BeforeEach(func() { - eventCh = make(chan interface{}) - - impl = implementation.NewGatewayClassImplementation(config.Config{ - Logger: zap.New(), - GatewayClassName: className, - }, eventCh) - }) - - Describe("Implementation processes GatewayClass", func() { - It("should process upsert", func() { - gc := &v1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: className, - }, - } - - go func() { - impl.Upsert(gc) - }() - - Eventually(eventCh).Should(Receive(Equal(&events.UpsertEvent{Resource: gc}))) - }) - - It("should process remove", func() { - nsname := types.NamespacedName{Name: className} - - go func() { - impl.Remove(nsname) - }() - - Eventually(eventCh).Should(Receive(Equal( - &events.DeleteEvent{ - NamespacedName: nsname, - Type: &v1beta1.GatewayClass{}, - }))) - }) - }) - - Describe("Implementation ignores unrelated GatewayClass", func() { - It("should ignore upsert", func() { - gc := &v1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: unrelatedClassName, - }, - } - - impl.Upsert(gc) - - Expect(eventCh).ShouldNot(Receive()) - }) - - It("should ignore remove", func() { - nsname := types.NamespacedName{Name: unrelatedClassName} - - impl.Remove(nsname) - - Expect(eventCh).ShouldNot(Receive()) - }) - }) -}) diff --git a/internal/implementations/gatewayclass/implementation_suite_test.go b/internal/implementations/gatewayclass/implementation_suite_test.go deleted file mode 100644 index a6f600b94c..0000000000 --- a/internal/implementations/gatewayclass/implementation_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package implementation_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestGatewayClassImplementation(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Gateway Class Implementation Suite") -} diff --git a/internal/implementations/httproute/httproute.go b/internal/implementations/httproute/httproute.go deleted file mode 100644 index 825d1df477..0000000000 --- a/internal/implementations/httproute/httproute.go +++ /dev/null @@ -1,53 +0,0 @@ -package implementation - -import ( - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -type httpRouteImplementation struct { - conf config.Config - eventCh chan<- interface{} -} - -// NewHTTPRouteImplementation creates a new HTTPRouteImplementation. -func NewHTTPRouteImplementation(cfg config.Config, eventCh chan<- interface{}) sdk.HTTPRouteImpl { - return &httpRouteImplementation{ - conf: cfg, - eventCh: eventCh, - } -} - -func (impl *httpRouteImplementation) Logger() logr.Logger { - return impl.conf.Logger -} - -func (impl *httpRouteImplementation) ControllerName() string { - return impl.conf.GatewayCtlrName -} - -func (impl *httpRouteImplementation) Upsert(hr *v1beta1.HTTPRoute) { - impl.Logger().Info("HTTPRoute was upserted", - "namespace", hr.Namespace, "name", hr.Name, - ) - - impl.eventCh <- &events.UpsertEvent{ - Resource: hr, - } -} - -func (impl *httpRouteImplementation) Remove(nsname types.NamespacedName) { - impl.Logger().Info("HTTPRoute resource was removed", - "namespace", nsname.Namespace, "name", nsname.Name, - ) - - impl.eventCh <- &events.DeleteEvent{ - NamespacedName: nsname, - Type: &v1beta1.HTTPRoute{}, - } -} diff --git a/internal/implementations/secret/implementation_suite_test.go b/internal/implementations/secret/implementation_suite_test.go deleted file mode 100644 index bfa87e8dfa..0000000000 --- a/internal/implementations/secret/implementation_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package implementation_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestSecretImplementation(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Secret Implementation Suite") -} diff --git a/internal/implementations/secret/secret.go b/internal/implementations/secret/secret.go deleted file mode 100644 index d3fbc9f285..0000000000 --- a/internal/implementations/secret/secret.go +++ /dev/null @@ -1,53 +0,0 @@ -package implementation - -import ( - "github.com/go-logr/logr" - apiv1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -type secretImplementation struct { - conf config.Config - eventCh chan<- interface{} -} - -// NewSecretImplementation creates a new SecretImplementation. -func NewSecretImplementation(cfg config.Config, eventCh chan<- interface{}) sdk.SecretImpl { - return &secretImplementation{ - conf: cfg, - eventCh: eventCh, - } -} - -func (impl *secretImplementation) Logger() logr.Logger { - return impl.conf.Logger -} - -func (impl secretImplementation) Upsert(secret *apiv1.Secret) { - impl.Logger().Info( - "Secret was upserted", - "namespace", secret.Namespace, - "name", secret.Name, - ) - - impl.eventCh <- &events.UpsertEvent{ - Resource: secret, - } -} - -func (impl secretImplementation) Remove(nsname types.NamespacedName) { - impl.Logger().Info( - "Secret was removed", - "namespace", nsname.Namespace, - "name", nsname.Name, - ) - - impl.eventCh <- &events.DeleteEvent{ - NamespacedName: nsname, - Type: &apiv1.Secret{}, - } -} diff --git a/internal/implementations/secret/secret_test.go b/internal/implementations/secret/secret_test.go deleted file mode 100644 index 8d0fc8dfd0..0000000000 --- a/internal/implementations/secret/secret_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package implementation_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - implementation "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/secret" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -var _ = Describe("SecretImplementation", func() { - var ( - eventCh chan interface{} - impl sdk.SecretImpl - ) - - BeforeEach(func() { - eventCh = make(chan interface{}) - - impl = implementation.NewSecretImplementation(config.Config{ - Logger: zap.New(), - }, eventCh) - }) - - const secretName = "my-secret" - const secretNamespace = "test" - - Describe("Implementation processes Secret", func() { - It("should process upsert", func() { - secret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: secretNamespace, - }, - } - - go func() { - impl.Upsert(secret) - }() - - Eventually(eventCh).Should(Receive(Equal(&events.UpsertEvent{Resource: secret}))) - }) - - It("should process remove", func() { - nsname := types.NamespacedName{Name: secretName, Namespace: secretNamespace} - - go func() { - impl.Remove(nsname) - }() - - Eventually(eventCh).Should(Receive(Equal( - &events.DeleteEvent{ - NamespacedName: nsname, - Type: &v1.Secret{}, - }))) - }) - }) -}) diff --git a/internal/implementations/service/service.go b/internal/implementations/service/service.go deleted file mode 100644 index a04cb12761..0000000000 --- a/internal/implementations/service/service.go +++ /dev/null @@ -1,52 +0,0 @@ -package implementation - -import ( - "github.com/go-logr/logr" - apiv1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - - "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" - "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" -) - -type serviceImplementation struct { - conf config.Config - eventCh chan<- interface{} -} - -// FIXME(pleshakov): serviceImplementation looks similar to httpRouteImplemenation -// consider if it is possible to reduce the amount of code. - -// NewServiceImplementation creates a new ServiceImplementation. -func NewServiceImplementation(cfg config.Config, eventCh chan<- interface{}) sdk.ServiceImpl { - return &serviceImplementation{ - conf: cfg, - eventCh: eventCh, - } -} - -func (impl *serviceImplementation) Logger() logr.Logger { - return impl.conf.Logger -} - -func (impl *serviceImplementation) Upsert(svc *apiv1.Service) { - impl.Logger().Info("Service was upserted", - "namespace", svc.Namespace, "name", svc.Name, - ) - - impl.eventCh <- &events.UpsertEvent{ - Resource: svc, - } -} - -func (impl *serviceImplementation) Remove(nsname types.NamespacedName) { - impl.Logger().Info("Service resource was removed", - "namespace", nsname.Namespace, "name", nsname.Name, - ) - - impl.eventCh <- &events.DeleteEvent{ - NamespacedName: nsname, - Type: &apiv1.Service{}, - } -} diff --git a/internal/manager/controllers.go b/internal/manager/controllers.go new file mode 100644 index 0000000000..0a2414ffa0 --- /dev/null +++ b/internal/manager/controllers.go @@ -0,0 +1,121 @@ +package manager + +import ( + "context" + "fmt" + "time" + + ctlr "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/index" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/reconciler" +) + +const ( + // addIndexFieldTimeout is the timeout used for adding an Index Field to a cache. + addIndexFieldTimeout = 2 * time.Minute +) + +type newReconcilerFunc func(cfg reconciler.Config) *reconciler.Implementation + +type controllerConfig struct { + namespacedNameFilter reconciler.NamespacedNameFilterFunc + k8sPredicate predicate.Predicate + fieldIndices index.FieldIndices + newReconciler newReconcilerFunc +} + +type controllerOption func(*controllerConfig) + +func withNamespacedNameFilter(filter reconciler.NamespacedNameFilterFunc) controllerOption { + return func(cfg *controllerConfig) { + cfg.namespacedNameFilter = filter + } +} + +func withK8sPredicate(p predicate.Predicate) controllerOption { + return func(cfg *controllerConfig) { + cfg.k8sPredicate = p + } +} + +func withFieldIndices(fieldIndices index.FieldIndices) controllerOption { + return func(cfg *controllerConfig) { + cfg.fieldIndices = fieldIndices + } +} + +// withNewReconciler allows us to mock reconciler creation in the unit tests. +func withNewReconciler(newReconciler newReconcilerFunc) controllerOption { + return func(cfg *controllerConfig) { + cfg.newReconciler = newReconciler + } +} + +func defaultControllerConfig() controllerConfig { + return controllerConfig{ + newReconciler: reconciler.NewImplementation, + } +} + +func registerController( + ctx context.Context, + objectType client.Object, + mgr manager.Manager, + eventCh chan interface{}, + options ...controllerOption, +) error { + cfg := defaultControllerConfig() + + for _, opt := range options { + opt(&cfg) + } + + for field, indexerFunc := range cfg.fieldIndices { + err := addIndex(ctx, mgr.GetFieldIndexer(), objectType, field, indexerFunc) + if err != nil { + return err + } + } + + builder := ctlr.NewControllerManagedBy(mgr).For(objectType) + + if cfg.k8sPredicate != nil { + builder = builder.WithEventFilter(cfg.k8sPredicate) + } + + recCfg := reconciler.Config{ + Getter: mgr.GetClient(), + ObjectType: objectType, + EventCh: eventCh, + NamespacedNameFilter: cfg.namespacedNameFilter, + } + + err := builder.Complete(cfg.newReconciler(recCfg)) + if err != nil { + return fmt.Errorf("cannot build a controller for %T: %w", objectType, err) + } + + return nil +} + +func addIndex( + ctx context.Context, + indexer client.FieldIndexer, + objectType client.Object, + field string, + indexerFunc client.IndexerFunc, +) error { + c, cancel := context.WithTimeout(ctx, addIndexFieldTimeout) + defer cancel() + + err := indexer.IndexField(c, objectType, field, indexerFunc) + if err != nil { + return fmt.Errorf("failed to add index for %T for field %s: %w", objectType, field, err) + } + + return nil +} diff --git a/internal/manager/controllers_test.go b/internal/manager/controllers_test.go new file mode 100644 index 0000000000..9a35574032 --- /dev/null +++ b/internal/manager/controllers_test.go @@ -0,0 +1,145 @@ +package manager + +import ( + "context" + "errors" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/gateway-api/apis/v1beta1" + + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/filter" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/index" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/managerfakes" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/predicate" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/reconciler" +) + +func TestRegisterController(t *testing.T) { + type fakes struct { + mgr *managerfakes.FakeManager + indexer *managerfakes.FakeFieldIndexer + } + + getDefaultFakes := func() fakes { + scheme = runtime.NewScheme() + utilruntime.Must(v1beta1.AddToScheme(scheme)) + + indexer := &managerfakes.FakeFieldIndexer{} + + mgr := &managerfakes.FakeManager{} + mgr.GetClientReturns(fake.NewClientBuilder().Build()) + mgr.GetSchemeReturns(scheme) + mgr.GetLoggerReturns(zap.New()) + mgr.GetFieldIndexerReturns(indexer) + + return fakes{ + mgr: mgr, + indexer: indexer, + } + } + + testError := errors.New("test error") + + tests := []struct { + fakes fakes + expectedErr error + expectedMgrAddCallCount int + msg string + }{ + { + fakes: getDefaultFakes(), + expectedErr: nil, + expectedMgrAddCallCount: 1, + msg: "normal case", + }, + { + fakes: func(f fakes) fakes { + f.indexer.IndexFieldReturns(testError) + return f + }(getDefaultFakes()), + expectedErr: testError, + expectedMgrAddCallCount: 0, + msg: "preparing index fails", + }, + { + fakes: func(f fakes) fakes { + f.mgr.AddReturns(testError) + return f + }(getDefaultFakes()), + expectedErr: testError, + expectedMgrAddCallCount: 1, + msg: "building controller fails", + }, + } + + objectType := &v1beta1.HTTPRoute{} + namespacedNameFilter := filter.CreateFilterForGatewayClass("test") + fieldIndexes := index.CreateEndpointSliceFieldIndices() + + eventCh := make(chan interface{}) + + for _, test := range tests { + newReconciler := func(c reconciler.Config) *reconciler.Implementation { + if c.Getter != test.fakes.mgr.GetClient() { + t.Errorf("regiterController() created a reconciler config with Getter %p but expected %p for case of %q", c.Getter, test.fakes.mgr.GetClient(), test.msg) + } + if c.ObjectType != objectType { + t.Errorf("registerController() created a reconciler config with ObjectType %T but expected %T for case of %q", c.ObjectType, objectType, test.msg) + } + if c.EventCh != eventCh { + t.Errorf("registerController() created a reconciler config with EventCh %v but expected %v for case of %q", c.EventCh, eventCh, test.msg) + } + // comparing functions is not allowed in Go, so we're comparing the pointers + if reflect.ValueOf(c.NamespacedNameFilter).Pointer() != reflect.ValueOf(namespacedNameFilter).Pointer() { + t.Errorf("registerController() created a reconciler config with NamespacedNameFilter %p but expected %p for case of %q", c.NamespacedNameFilter, namespacedNameFilter, test.msg) + } + + return reconciler.NewImplementation(c) + } + + err := registerController( + context.Background(), + objectType, + test.fakes.mgr, + eventCh, + withNamespacedNameFilter(namespacedNameFilter), + withK8sPredicate(predicate.ServicePortsChangedPredicate{}), + withFieldIndices(fieldIndexes), + withNewReconciler(newReconciler), + ) + + if !errors.Is(err, test.expectedErr) { + t.Errorf("registerController() returned %q but expected %q for case of %q", err, test.expectedErr, test.msg) + } + + indexCallCount := test.fakes.indexer.IndexFieldCallCount() + if indexCallCount != 1 { + t.Errorf("registerController() called indexer.IndexField() %d times but expected 1 for case of %q", indexCallCount, test.msg) + } else { + _, objType, field, indexFunc := test.fakes.indexer.IndexFieldArgsForCall(0) + + if objType != objectType { + t.Errorf("registerController() called indexer.IndexField() with object type %T but expected %T for case of %q", objType, objectType, test.msg) + } + if field != index.KubernetesServiceNameIndexField { + t.Errorf("registerController() called indexer.IndexField() with field %q but expected %q for case of %q", field, index.KubernetesServiceNameIndexField, test.msg) + } + + expectedIndexFunc := fieldIndexes[index.KubernetesServiceNameIndexField] + // comparing functions is not allowed in Go, so we're comparing the pointers + if reflect.ValueOf(indexFunc).Pointer() != reflect.ValueOf(expectedIndexFunc).Pointer() { + t.Errorf("registerController() called indexer.IndexField() with indexFunc %p but expected %p for case of %q", indexFunc, expectedIndexFunc, test.msg) + } + } + + addCallCount := test.fakes.mgr.AddCallCount() + if addCallCount != test.expectedMgrAddCallCount { + t.Errorf("registerController() called mgr.Add() %d times but expected %d times for case of %q", addCallCount, test.expectedMgrAddCallCount, test.msg) + } + } +} diff --git a/internal/manager/fakes.go b/internal/manager/fakes.go new file mode 100644 index 0000000000..976418110e --- /dev/null +++ b/internal/manager/fakes.go @@ -0,0 +1,10 @@ +package manager + +import ( + _ "sigs.k8s.io/controller-runtime/pkg/client" // used below to generate a fake + _ "sigs.k8s.io/controller-runtime/pkg/manager" // used below to generate a fake +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 sigs.k8s.io/controller-runtime/pkg/manager.Manager + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 sigs.k8s.io/controller-runtime/pkg/client.FieldIndexer diff --git a/internal/manager/filter/gatewayclass.go b/internal/manager/filter/gatewayclass.go new file mode 100644 index 0000000000..4a85a59247 --- /dev/null +++ b/internal/manager/filter/gatewayclass.go @@ -0,0 +1,20 @@ +package filter + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/types" + + "github.com/nginxinc/nginx-kubernetes-gateway/internal/reconciler" +) + +// CreateFilterForGatewayClass creates a filter function that filters out all GatewayClass resources except the one +// with the given name. +func CreateFilterForGatewayClass(gcName string) reconciler.NamespacedNameFilterFunc { + return func(nsname types.NamespacedName) (bool, string) { + if nsname.Name != gcName { + return false, fmt.Sprintf("GatewayClass is ignored because this controller only supports the GatewayClass %s", gcName) + } + return true, "" + } +} diff --git a/internal/manager/filter/gatewayclass_test.go b/internal/manager/filter/gatewayclass_test.go new file mode 100644 index 0000000000..d8c9c309ed --- /dev/null +++ b/internal/manager/filter/gatewayclass_test.go @@ -0,0 +1,49 @@ +package filter + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" +) + +func TestCreateFilterForGatewayClass(t *testing.T) { + const gcName = "my-gc" + + filter := CreateFilterForGatewayClass(gcName) + if filter == nil { + t.Fatal("CreateFilterForGatewayClass() returned nil") + } + + tests := []struct { + nsname types.NamespacedName + expected bool + }{ + { + nsname: types.NamespacedName{Name: gcName}, + expected: true, + }, + { + nsname: types.NamespacedName{Name: gcName, Namespace: "doesn't matter"}, + expected: true, + }, + { + nsname: types.NamespacedName{Name: "some-gc"}, + expected: false, + }, + } + + for _, test := range tests { + result, msg := filter(test.nsname) + + if result != test.expected { + t.Errorf("filter(%#v) returned %v but expected %v", test.nsname, result, test.expected) + } + + if result && msg != "" { + t.Errorf("filter(%#v) returned a non-empty message %q", test.nsname, msg) + } + if !result && msg == "" { + t.Errorf("filter(%#v) returned an empty message", test.nsname) + } + } +} diff --git a/internal/manager/index/endpointslice.go b/internal/manager/index/endpointslice.go new file mode 100644 index 0000000000..5915586277 --- /dev/null +++ b/internal/manager/index/endpointslice.go @@ -0,0 +1,49 @@ +package index + +import ( + "fmt" + + discoveryV1 "k8s.io/api/discovery/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + // KubernetesServiceNameIndexField is the name of the Index Field used to index EndpointSlices by their service + // owners. + KubernetesServiceNameIndexField = "k8sServiceName" + // KubernetesServiceNameLabel is the label used to identify the Kubernetes service name on an EndpointSlice. + KubernetesServiceNameLabel = "kubernetes.io/service-name" +) + +// CreateEndpointSliceFieldIndices creates a FieldIndices map for the EndpointSlice resource. +func CreateEndpointSliceFieldIndices() FieldIndices { + return FieldIndices{ + KubernetesServiceNameIndexField: serviceNameIndexFunc, + } +} + +// serviceNameIndexFunc is a client.IndexerFunc that parses a Kubernetes object and returns the value of the +// Kubernetes service-name label. +// Used to index EndpointSlices by their service owners. +func serviceNameIndexFunc(obj client.Object) []string { + slice, ok := obj.(*discoveryV1.EndpointSlice) + if !ok { + panic(fmt.Sprintf("expected an EndpointSlice; got %T", obj)) + } + + name := GetServiceNameFromEndpointSlice(slice) + if name == "" { + return nil + } + + return []string{name} +} + +// GetServiceNameFromEndpointSlice returns the value of the Kubernetes service-name label from an EndpointSlice. +func GetServiceNameFromEndpointSlice(slice *discoveryV1.EndpointSlice) string { + if slice.Labels == nil { + return "" + } + + return slice.Labels[KubernetesServiceNameLabel] +} diff --git a/pkg/sdk/endpointslice_test.go b/internal/manager/index/endpointslice_test.go similarity index 74% rename from pkg/sdk/endpointslice_test.go rename to internal/manager/index/endpointslice_test.go index 323c952d62..f1d281bcdc 100644 --- a/pkg/sdk/endpointslice_test.go +++ b/internal/manager/index/endpointslice_test.go @@ -1,4 +1,4 @@ -package sdk_test +package index import ( "testing" @@ -8,8 +8,6 @@ import ( discoveryV1 "k8s.io/api/discovery/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" ) func TestServiceNameIndexFunc(t *testing.T) { @@ -22,7 +20,7 @@ func TestServiceNameIndexFunc(t *testing.T) { msg: "normal case", obj: &discoveryV1.EndpointSlice{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{sdk.KubernetesServiceNameLabel: "test-svc"}, + Labels: map[string]string{KubernetesServiceNameLabel: "test-svc"}, }, }, expOutput: []string{"test-svc"}, @@ -44,9 +42,9 @@ func TestServiceNameIndexFunc(t *testing.T) { } for _, tc := range testcases { - output := sdk.ServiceNameIndexFunc(tc.obj) + output := serviceNameIndexFunc(tc.obj) if diff := cmp.Diff(tc.expOutput, output); diff != "" { - t.Errorf("ServiceNameIndexFunc() mismatch on %q (-want +got):\n%s", tc.msg, diff) + t.Errorf("serviceNameIndexFunc() mismatch on %q (-want +got):\n%s", tc.msg, diff) } } } @@ -54,9 +52,9 @@ func TestServiceNameIndexFunc(t *testing.T) { func TestServiceNameIndexFuncPanics(t *testing.T) { defer func() { if r := recover(); r == nil { - t.Errorf("ServiceNameIndexFunc() did not panic") + t.Errorf("serviceNameIndexFunc() did not panic") } }() - sdk.ServiceNameIndexFunc(&v1.Namespace{}) + serviceNameIndexFunc(&v1.Namespace{}) } diff --git a/internal/manager/index/index.go b/internal/manager/index/index.go new file mode 100644 index 0000000000..0a7f5e0b58 --- /dev/null +++ b/internal/manager/index/index.go @@ -0,0 +1,6 @@ +package index + +import "sigs.k8s.io/controller-runtime/pkg/client" + +// FieldIndices is a map of field names to their indexer functions. +type FieldIndices map[string]client.IndexerFunc diff --git a/internal/manager/manager.go b/internal/manager/manager.go index 40d54a3e17..b7cb1cffd6 100644 --- a/internal/manager/manager.go +++ b/internal/manager/manager.go @@ -12,16 +12,14 @@ import ( ctlr "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" + k8spredicate "sigs.k8s.io/controller-runtime/pkg/predicate" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/nginxinc/nginx-kubernetes-gateway/internal/config" "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" - endpointslice "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/endpointslice" - gw "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/gateway" - gc "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/gatewayclass" - hr "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/httproute" - secret "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/secret" - svc "github.com/nginxinc/nginx-kubernetes-gateway/internal/implementations/service" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/filter" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/index" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/predicate" ngxcfg "github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/config" "github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/file" ngxruntime "github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/runtime" @@ -29,7 +27,6 @@ import ( "github.com/nginxinc/nginx-kubernetes-gateway/internal/state/relationship" "github.com/nginxinc/nginx-kubernetes-gateway/internal/state/resolver" "github.com/nginxinc/nginx-kubernetes-gateway/internal/status" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" ) const ( @@ -53,6 +50,7 @@ func Start(cfg config.Config) error { options := manager.Options{ Scheme: scheme, + Logger: logger, } eventCh := make(chan interface{}) @@ -65,32 +63,47 @@ func Start(cfg config.Config) error { return fmt.Errorf("cannot build runtime manager: %w", err) } - err = sdk.RegisterGatewayClassController(mgr, gc.NewGatewayClassImplementation(cfg, eventCh)) - if err != nil { - return fmt.Errorf("cannot register gatewayclass implementation: %w", err) - } - err = sdk.RegisterGatewayController(mgr, gw.NewGatewayImplementation(cfg, eventCh)) - if err != nil { - return fmt.Errorf("cannot register gateway implementation: %w", err) - } - err = sdk.RegisterHTTPRouteController(mgr, hr.NewHTTPRouteImplementation(cfg, eventCh)) - if err != nil { - return fmt.Errorf("cannot register httproute implementation: %w", err) - } - err = sdk.RegisterServiceController(mgr, svc.NewServiceImplementation(cfg, eventCh)) - if err != nil { - return fmt.Errorf("cannot register service implementation: %w", err) - } - err = sdk.RegisterSecretController(mgr, secret.NewSecretImplementation(cfg, eventCh)) - if err != nil { - return fmt.Errorf("cannot register secret implementation: %w", err) + controllerRegCfgs := []struct { + objectType client.Object + options []controllerOption + }{ + { + objectType: &gatewayv1beta1.GatewayClass{}, + options: []controllerOption{ + withNamespacedNameFilter(filter.CreateFilterForGatewayClass(cfg.GatewayClassName)), + }, + }, + { + objectType: &gatewayv1beta1.Gateway{}, + }, + { + objectType: &gatewayv1beta1.HTTPRoute{}, + }, + { + objectType: &apiv1.Service{}, + options: []controllerOption{ + withK8sPredicate(predicate.ServicePortsChangedPredicate{}), + }, + }, + { + objectType: &apiv1.Secret{}, + }, + { + objectType: &discoveryV1.EndpointSlice{}, + options: []controllerOption{ + withK8sPredicate(k8spredicate.GenerationChangedPredicate{}), + withFieldIndices(index.CreateEndpointSliceFieldIndices()), + }, + }, } ctx := ctlr.SetupSignalHandler() - err = sdk.RegisterEndpointSliceController(ctx, mgr, endpointslice.NewEndpointSliceImplementation(cfg, eventCh)) - if err != nil { - return fmt.Errorf("cannot register endpointslice implementation: %w", err) + for _, regCfg := range controllerRegCfgs { + err := registerController(ctx, regCfg.objectType, mgr, eventCh, regCfg.options...) + if err != nil { + return fmt.Errorf("cannot register controller for %T: %w", regCfg.objectType, err) + } } secretStore := state.NewSecretStore() diff --git a/internal/manager/managerfakes/fake_field_indexer.go b/internal/manager/managerfakes/fake_field_indexer.go new file mode 100644 index 0000000000..1a7c16e6a5 --- /dev/null +++ b/internal/manager/managerfakes/fake_field_indexer.go @@ -0,0 +1,118 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package managerfakes + +import ( + "context" + "sync" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type FakeFieldIndexer struct { + IndexFieldStub func(context.Context, client.Object, string, client.IndexerFunc) error + indexFieldMutex sync.RWMutex + indexFieldArgsForCall []struct { + arg1 context.Context + arg2 client.Object + arg3 string + arg4 client.IndexerFunc + } + indexFieldReturns struct { + result1 error + } + indexFieldReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeFieldIndexer) IndexField(arg1 context.Context, arg2 client.Object, arg3 string, arg4 client.IndexerFunc) error { + fake.indexFieldMutex.Lock() + ret, specificReturn := fake.indexFieldReturnsOnCall[len(fake.indexFieldArgsForCall)] + fake.indexFieldArgsForCall = append(fake.indexFieldArgsForCall, struct { + arg1 context.Context + arg2 client.Object + arg3 string + arg4 client.IndexerFunc + }{arg1, arg2, arg3, arg4}) + stub := fake.IndexFieldStub + fakeReturns := fake.indexFieldReturns + fake.recordInvocation("IndexField", []interface{}{arg1, arg2, arg3, arg4}) + fake.indexFieldMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeFieldIndexer) IndexFieldCallCount() int { + fake.indexFieldMutex.RLock() + defer fake.indexFieldMutex.RUnlock() + return len(fake.indexFieldArgsForCall) +} + +func (fake *FakeFieldIndexer) IndexFieldCalls(stub func(context.Context, client.Object, string, client.IndexerFunc) error) { + fake.indexFieldMutex.Lock() + defer fake.indexFieldMutex.Unlock() + fake.IndexFieldStub = stub +} + +func (fake *FakeFieldIndexer) IndexFieldArgsForCall(i int) (context.Context, client.Object, string, client.IndexerFunc) { + fake.indexFieldMutex.RLock() + defer fake.indexFieldMutex.RUnlock() + argsForCall := fake.indexFieldArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeFieldIndexer) IndexFieldReturns(result1 error) { + fake.indexFieldMutex.Lock() + defer fake.indexFieldMutex.Unlock() + fake.IndexFieldStub = nil + fake.indexFieldReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeFieldIndexer) IndexFieldReturnsOnCall(i int, result1 error) { + fake.indexFieldMutex.Lock() + defer fake.indexFieldMutex.Unlock() + fake.IndexFieldStub = nil + if fake.indexFieldReturnsOnCall == nil { + fake.indexFieldReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.indexFieldReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeFieldIndexer) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.indexFieldMutex.RLock() + defer fake.indexFieldMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeFieldIndexer) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ client.FieldIndexer = new(FakeFieldIndexer) diff --git a/internal/manager/managerfakes/fake_manager.go b/internal/manager/managerfakes/fake_manager.go new file mode 100644 index 0000000000..0091cacab5 --- /dev/null +++ b/internal/manager/managerfakes/fake_manager.go @@ -0,0 +1,1288 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package managerfakes + +import ( + "context" + "net/http" + "sync" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +type FakeManager struct { + AddStub func(manager.Runnable) error + addMutex sync.RWMutex + addArgsForCall []struct { + arg1 manager.Runnable + } + addReturns struct { + result1 error + } + addReturnsOnCall map[int]struct { + result1 error + } + AddHealthzCheckStub func(string, healthz.Checker) error + addHealthzCheckMutex sync.RWMutex + addHealthzCheckArgsForCall []struct { + arg1 string + arg2 healthz.Checker + } + addHealthzCheckReturns struct { + result1 error + } + addHealthzCheckReturnsOnCall map[int]struct { + result1 error + } + AddMetricsExtraHandlerStub func(string, http.Handler) error + addMetricsExtraHandlerMutex sync.RWMutex + addMetricsExtraHandlerArgsForCall []struct { + arg1 string + arg2 http.Handler + } + addMetricsExtraHandlerReturns struct { + result1 error + } + addMetricsExtraHandlerReturnsOnCall map[int]struct { + result1 error + } + AddReadyzCheckStub func(string, healthz.Checker) error + addReadyzCheckMutex sync.RWMutex + addReadyzCheckArgsForCall []struct { + arg1 string + arg2 healthz.Checker + } + addReadyzCheckReturns struct { + result1 error + } + addReadyzCheckReturnsOnCall map[int]struct { + result1 error + } + ElectedStub func() <-chan struct{} + electedMutex sync.RWMutex + electedArgsForCall []struct { + } + electedReturns struct { + result1 <-chan struct{} + } + electedReturnsOnCall map[int]struct { + result1 <-chan struct{} + } + GetAPIReaderStub func() client.Reader + getAPIReaderMutex sync.RWMutex + getAPIReaderArgsForCall []struct { + } + getAPIReaderReturns struct { + result1 client.Reader + } + getAPIReaderReturnsOnCall map[int]struct { + result1 client.Reader + } + GetCacheStub func() cache.Cache + getCacheMutex sync.RWMutex + getCacheArgsForCall []struct { + } + getCacheReturns struct { + result1 cache.Cache + } + getCacheReturnsOnCall map[int]struct { + result1 cache.Cache + } + GetClientStub func() client.Client + getClientMutex sync.RWMutex + getClientArgsForCall []struct { + } + getClientReturns struct { + result1 client.Client + } + getClientReturnsOnCall map[int]struct { + result1 client.Client + } + GetConfigStub func() *rest.Config + getConfigMutex sync.RWMutex + getConfigArgsForCall []struct { + } + getConfigReturns struct { + result1 *rest.Config + } + getConfigReturnsOnCall map[int]struct { + result1 *rest.Config + } + GetControllerOptionsStub func() v1alpha1.ControllerConfigurationSpec + getControllerOptionsMutex sync.RWMutex + getControllerOptionsArgsForCall []struct { + } + getControllerOptionsReturns struct { + result1 v1alpha1.ControllerConfigurationSpec + } + getControllerOptionsReturnsOnCall map[int]struct { + result1 v1alpha1.ControllerConfigurationSpec + } + GetEventRecorderForStub func(string) record.EventRecorder + getEventRecorderForMutex sync.RWMutex + getEventRecorderForArgsForCall []struct { + arg1 string + } + getEventRecorderForReturns struct { + result1 record.EventRecorder + } + getEventRecorderForReturnsOnCall map[int]struct { + result1 record.EventRecorder + } + GetFieldIndexerStub func() client.FieldIndexer + getFieldIndexerMutex sync.RWMutex + getFieldIndexerArgsForCall []struct { + } + getFieldIndexerReturns struct { + result1 client.FieldIndexer + } + getFieldIndexerReturnsOnCall map[int]struct { + result1 client.FieldIndexer + } + GetLoggerStub func() logr.Logger + getLoggerMutex sync.RWMutex + getLoggerArgsForCall []struct { + } + getLoggerReturns struct { + result1 logr.Logger + } + getLoggerReturnsOnCall map[int]struct { + result1 logr.Logger + } + GetRESTMapperStub func() meta.RESTMapper + getRESTMapperMutex sync.RWMutex + getRESTMapperArgsForCall []struct { + } + getRESTMapperReturns struct { + result1 meta.RESTMapper + } + getRESTMapperReturnsOnCall map[int]struct { + result1 meta.RESTMapper + } + GetSchemeStub func() *runtime.Scheme + getSchemeMutex sync.RWMutex + getSchemeArgsForCall []struct { + } + getSchemeReturns struct { + result1 *runtime.Scheme + } + getSchemeReturnsOnCall map[int]struct { + result1 *runtime.Scheme + } + GetWebhookServerStub func() *webhook.Server + getWebhookServerMutex sync.RWMutex + getWebhookServerArgsForCall []struct { + } + getWebhookServerReturns struct { + result1 *webhook.Server + } + getWebhookServerReturnsOnCall map[int]struct { + result1 *webhook.Server + } + SetFieldsStub func(interface{}) error + setFieldsMutex sync.RWMutex + setFieldsArgsForCall []struct { + arg1 interface{} + } + setFieldsReturns struct { + result1 error + } + setFieldsReturnsOnCall map[int]struct { + result1 error + } + StartStub func(context.Context) error + startMutex sync.RWMutex + startArgsForCall []struct { + arg1 context.Context + } + startReturns struct { + result1 error + } + startReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeManager) Add(arg1 manager.Runnable) error { + fake.addMutex.Lock() + ret, specificReturn := fake.addReturnsOnCall[len(fake.addArgsForCall)] + fake.addArgsForCall = append(fake.addArgsForCall, struct { + arg1 manager.Runnable + }{arg1}) + stub := fake.AddStub + fakeReturns := fake.addReturns + fake.recordInvocation("Add", []interface{}{arg1}) + fake.addMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) AddCallCount() int { + fake.addMutex.RLock() + defer fake.addMutex.RUnlock() + return len(fake.addArgsForCall) +} + +func (fake *FakeManager) AddCalls(stub func(manager.Runnable) error) { + fake.addMutex.Lock() + defer fake.addMutex.Unlock() + fake.AddStub = stub +} + +func (fake *FakeManager) AddArgsForCall(i int) manager.Runnable { + fake.addMutex.RLock() + defer fake.addMutex.RUnlock() + argsForCall := fake.addArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeManager) AddReturns(result1 error) { + fake.addMutex.Lock() + defer fake.addMutex.Unlock() + fake.AddStub = nil + fake.addReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) AddReturnsOnCall(i int, result1 error) { + fake.addMutex.Lock() + defer fake.addMutex.Unlock() + fake.AddStub = nil + if fake.addReturnsOnCall == nil { + fake.addReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.addReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) AddHealthzCheck(arg1 string, arg2 healthz.Checker) error { + fake.addHealthzCheckMutex.Lock() + ret, specificReturn := fake.addHealthzCheckReturnsOnCall[len(fake.addHealthzCheckArgsForCall)] + fake.addHealthzCheckArgsForCall = append(fake.addHealthzCheckArgsForCall, struct { + arg1 string + arg2 healthz.Checker + }{arg1, arg2}) + stub := fake.AddHealthzCheckStub + fakeReturns := fake.addHealthzCheckReturns + fake.recordInvocation("AddHealthzCheck", []interface{}{arg1, arg2}) + fake.addHealthzCheckMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) AddHealthzCheckCallCount() int { + fake.addHealthzCheckMutex.RLock() + defer fake.addHealthzCheckMutex.RUnlock() + return len(fake.addHealthzCheckArgsForCall) +} + +func (fake *FakeManager) AddHealthzCheckCalls(stub func(string, healthz.Checker) error) { + fake.addHealthzCheckMutex.Lock() + defer fake.addHealthzCheckMutex.Unlock() + fake.AddHealthzCheckStub = stub +} + +func (fake *FakeManager) AddHealthzCheckArgsForCall(i int) (string, healthz.Checker) { + fake.addHealthzCheckMutex.RLock() + defer fake.addHealthzCheckMutex.RUnlock() + argsForCall := fake.addHealthzCheckArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeManager) AddHealthzCheckReturns(result1 error) { + fake.addHealthzCheckMutex.Lock() + defer fake.addHealthzCheckMutex.Unlock() + fake.AddHealthzCheckStub = nil + fake.addHealthzCheckReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) AddHealthzCheckReturnsOnCall(i int, result1 error) { + fake.addHealthzCheckMutex.Lock() + defer fake.addHealthzCheckMutex.Unlock() + fake.AddHealthzCheckStub = nil + if fake.addHealthzCheckReturnsOnCall == nil { + fake.addHealthzCheckReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.addHealthzCheckReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) AddMetricsExtraHandler(arg1 string, arg2 http.Handler) error { + fake.addMetricsExtraHandlerMutex.Lock() + ret, specificReturn := fake.addMetricsExtraHandlerReturnsOnCall[len(fake.addMetricsExtraHandlerArgsForCall)] + fake.addMetricsExtraHandlerArgsForCall = append(fake.addMetricsExtraHandlerArgsForCall, struct { + arg1 string + arg2 http.Handler + }{arg1, arg2}) + stub := fake.AddMetricsExtraHandlerStub + fakeReturns := fake.addMetricsExtraHandlerReturns + fake.recordInvocation("AddMetricsExtraHandler", []interface{}{arg1, arg2}) + fake.addMetricsExtraHandlerMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) AddMetricsExtraHandlerCallCount() int { + fake.addMetricsExtraHandlerMutex.RLock() + defer fake.addMetricsExtraHandlerMutex.RUnlock() + return len(fake.addMetricsExtraHandlerArgsForCall) +} + +func (fake *FakeManager) AddMetricsExtraHandlerCalls(stub func(string, http.Handler) error) { + fake.addMetricsExtraHandlerMutex.Lock() + defer fake.addMetricsExtraHandlerMutex.Unlock() + fake.AddMetricsExtraHandlerStub = stub +} + +func (fake *FakeManager) AddMetricsExtraHandlerArgsForCall(i int) (string, http.Handler) { + fake.addMetricsExtraHandlerMutex.RLock() + defer fake.addMetricsExtraHandlerMutex.RUnlock() + argsForCall := fake.addMetricsExtraHandlerArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeManager) AddMetricsExtraHandlerReturns(result1 error) { + fake.addMetricsExtraHandlerMutex.Lock() + defer fake.addMetricsExtraHandlerMutex.Unlock() + fake.AddMetricsExtraHandlerStub = nil + fake.addMetricsExtraHandlerReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) AddMetricsExtraHandlerReturnsOnCall(i int, result1 error) { + fake.addMetricsExtraHandlerMutex.Lock() + defer fake.addMetricsExtraHandlerMutex.Unlock() + fake.AddMetricsExtraHandlerStub = nil + if fake.addMetricsExtraHandlerReturnsOnCall == nil { + fake.addMetricsExtraHandlerReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.addMetricsExtraHandlerReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) AddReadyzCheck(arg1 string, arg2 healthz.Checker) error { + fake.addReadyzCheckMutex.Lock() + ret, specificReturn := fake.addReadyzCheckReturnsOnCall[len(fake.addReadyzCheckArgsForCall)] + fake.addReadyzCheckArgsForCall = append(fake.addReadyzCheckArgsForCall, struct { + arg1 string + arg2 healthz.Checker + }{arg1, arg2}) + stub := fake.AddReadyzCheckStub + fakeReturns := fake.addReadyzCheckReturns + fake.recordInvocation("AddReadyzCheck", []interface{}{arg1, arg2}) + fake.addReadyzCheckMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) AddReadyzCheckCallCount() int { + fake.addReadyzCheckMutex.RLock() + defer fake.addReadyzCheckMutex.RUnlock() + return len(fake.addReadyzCheckArgsForCall) +} + +func (fake *FakeManager) AddReadyzCheckCalls(stub func(string, healthz.Checker) error) { + fake.addReadyzCheckMutex.Lock() + defer fake.addReadyzCheckMutex.Unlock() + fake.AddReadyzCheckStub = stub +} + +func (fake *FakeManager) AddReadyzCheckArgsForCall(i int) (string, healthz.Checker) { + fake.addReadyzCheckMutex.RLock() + defer fake.addReadyzCheckMutex.RUnlock() + argsForCall := fake.addReadyzCheckArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeManager) AddReadyzCheckReturns(result1 error) { + fake.addReadyzCheckMutex.Lock() + defer fake.addReadyzCheckMutex.Unlock() + fake.AddReadyzCheckStub = nil + fake.addReadyzCheckReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) AddReadyzCheckReturnsOnCall(i int, result1 error) { + fake.addReadyzCheckMutex.Lock() + defer fake.addReadyzCheckMutex.Unlock() + fake.AddReadyzCheckStub = nil + if fake.addReadyzCheckReturnsOnCall == nil { + fake.addReadyzCheckReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.addReadyzCheckReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) Elected() <-chan struct{} { + fake.electedMutex.Lock() + ret, specificReturn := fake.electedReturnsOnCall[len(fake.electedArgsForCall)] + fake.electedArgsForCall = append(fake.electedArgsForCall, struct { + }{}) + stub := fake.ElectedStub + fakeReturns := fake.electedReturns + fake.recordInvocation("Elected", []interface{}{}) + fake.electedMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) ElectedCallCount() int { + fake.electedMutex.RLock() + defer fake.electedMutex.RUnlock() + return len(fake.electedArgsForCall) +} + +func (fake *FakeManager) ElectedCalls(stub func() <-chan struct{}) { + fake.electedMutex.Lock() + defer fake.electedMutex.Unlock() + fake.ElectedStub = stub +} + +func (fake *FakeManager) ElectedReturns(result1 <-chan struct{}) { + fake.electedMutex.Lock() + defer fake.electedMutex.Unlock() + fake.ElectedStub = nil + fake.electedReturns = struct { + result1 <-chan struct{} + }{result1} +} + +func (fake *FakeManager) ElectedReturnsOnCall(i int, result1 <-chan struct{}) { + fake.electedMutex.Lock() + defer fake.electedMutex.Unlock() + fake.ElectedStub = nil + if fake.electedReturnsOnCall == nil { + fake.electedReturnsOnCall = make(map[int]struct { + result1 <-chan struct{} + }) + } + fake.electedReturnsOnCall[i] = struct { + result1 <-chan struct{} + }{result1} +} + +func (fake *FakeManager) GetAPIReader() client.Reader { + fake.getAPIReaderMutex.Lock() + ret, specificReturn := fake.getAPIReaderReturnsOnCall[len(fake.getAPIReaderArgsForCall)] + fake.getAPIReaderArgsForCall = append(fake.getAPIReaderArgsForCall, struct { + }{}) + stub := fake.GetAPIReaderStub + fakeReturns := fake.getAPIReaderReturns + fake.recordInvocation("GetAPIReader", []interface{}{}) + fake.getAPIReaderMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetAPIReaderCallCount() int { + fake.getAPIReaderMutex.RLock() + defer fake.getAPIReaderMutex.RUnlock() + return len(fake.getAPIReaderArgsForCall) +} + +func (fake *FakeManager) GetAPIReaderCalls(stub func() client.Reader) { + fake.getAPIReaderMutex.Lock() + defer fake.getAPIReaderMutex.Unlock() + fake.GetAPIReaderStub = stub +} + +func (fake *FakeManager) GetAPIReaderReturns(result1 client.Reader) { + fake.getAPIReaderMutex.Lock() + defer fake.getAPIReaderMutex.Unlock() + fake.GetAPIReaderStub = nil + fake.getAPIReaderReturns = struct { + result1 client.Reader + }{result1} +} + +func (fake *FakeManager) GetAPIReaderReturnsOnCall(i int, result1 client.Reader) { + fake.getAPIReaderMutex.Lock() + defer fake.getAPIReaderMutex.Unlock() + fake.GetAPIReaderStub = nil + if fake.getAPIReaderReturnsOnCall == nil { + fake.getAPIReaderReturnsOnCall = make(map[int]struct { + result1 client.Reader + }) + } + fake.getAPIReaderReturnsOnCall[i] = struct { + result1 client.Reader + }{result1} +} + +func (fake *FakeManager) GetCache() cache.Cache { + fake.getCacheMutex.Lock() + ret, specificReturn := fake.getCacheReturnsOnCall[len(fake.getCacheArgsForCall)] + fake.getCacheArgsForCall = append(fake.getCacheArgsForCall, struct { + }{}) + stub := fake.GetCacheStub + fakeReturns := fake.getCacheReturns + fake.recordInvocation("GetCache", []interface{}{}) + fake.getCacheMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetCacheCallCount() int { + fake.getCacheMutex.RLock() + defer fake.getCacheMutex.RUnlock() + return len(fake.getCacheArgsForCall) +} + +func (fake *FakeManager) GetCacheCalls(stub func() cache.Cache) { + fake.getCacheMutex.Lock() + defer fake.getCacheMutex.Unlock() + fake.GetCacheStub = stub +} + +func (fake *FakeManager) GetCacheReturns(result1 cache.Cache) { + fake.getCacheMutex.Lock() + defer fake.getCacheMutex.Unlock() + fake.GetCacheStub = nil + fake.getCacheReturns = struct { + result1 cache.Cache + }{result1} +} + +func (fake *FakeManager) GetCacheReturnsOnCall(i int, result1 cache.Cache) { + fake.getCacheMutex.Lock() + defer fake.getCacheMutex.Unlock() + fake.GetCacheStub = nil + if fake.getCacheReturnsOnCall == nil { + fake.getCacheReturnsOnCall = make(map[int]struct { + result1 cache.Cache + }) + } + fake.getCacheReturnsOnCall[i] = struct { + result1 cache.Cache + }{result1} +} + +func (fake *FakeManager) GetClient() client.Client { + fake.getClientMutex.Lock() + ret, specificReturn := fake.getClientReturnsOnCall[len(fake.getClientArgsForCall)] + fake.getClientArgsForCall = append(fake.getClientArgsForCall, struct { + }{}) + stub := fake.GetClientStub + fakeReturns := fake.getClientReturns + fake.recordInvocation("GetClient", []interface{}{}) + fake.getClientMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetClientCallCount() int { + fake.getClientMutex.RLock() + defer fake.getClientMutex.RUnlock() + return len(fake.getClientArgsForCall) +} + +func (fake *FakeManager) GetClientCalls(stub func() client.Client) { + fake.getClientMutex.Lock() + defer fake.getClientMutex.Unlock() + fake.GetClientStub = stub +} + +func (fake *FakeManager) GetClientReturns(result1 client.Client) { + fake.getClientMutex.Lock() + defer fake.getClientMutex.Unlock() + fake.GetClientStub = nil + fake.getClientReturns = struct { + result1 client.Client + }{result1} +} + +func (fake *FakeManager) GetClientReturnsOnCall(i int, result1 client.Client) { + fake.getClientMutex.Lock() + defer fake.getClientMutex.Unlock() + fake.GetClientStub = nil + if fake.getClientReturnsOnCall == nil { + fake.getClientReturnsOnCall = make(map[int]struct { + result1 client.Client + }) + } + fake.getClientReturnsOnCall[i] = struct { + result1 client.Client + }{result1} +} + +func (fake *FakeManager) GetConfig() *rest.Config { + fake.getConfigMutex.Lock() + ret, specificReturn := fake.getConfigReturnsOnCall[len(fake.getConfigArgsForCall)] + fake.getConfigArgsForCall = append(fake.getConfigArgsForCall, struct { + }{}) + stub := fake.GetConfigStub + fakeReturns := fake.getConfigReturns + fake.recordInvocation("GetConfig", []interface{}{}) + fake.getConfigMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetConfigCallCount() int { + fake.getConfigMutex.RLock() + defer fake.getConfigMutex.RUnlock() + return len(fake.getConfigArgsForCall) +} + +func (fake *FakeManager) GetConfigCalls(stub func() *rest.Config) { + fake.getConfigMutex.Lock() + defer fake.getConfigMutex.Unlock() + fake.GetConfigStub = stub +} + +func (fake *FakeManager) GetConfigReturns(result1 *rest.Config) { + fake.getConfigMutex.Lock() + defer fake.getConfigMutex.Unlock() + fake.GetConfigStub = nil + fake.getConfigReturns = struct { + result1 *rest.Config + }{result1} +} + +func (fake *FakeManager) GetConfigReturnsOnCall(i int, result1 *rest.Config) { + fake.getConfigMutex.Lock() + defer fake.getConfigMutex.Unlock() + fake.GetConfigStub = nil + if fake.getConfigReturnsOnCall == nil { + fake.getConfigReturnsOnCall = make(map[int]struct { + result1 *rest.Config + }) + } + fake.getConfigReturnsOnCall[i] = struct { + result1 *rest.Config + }{result1} +} + +func (fake *FakeManager) GetControllerOptions() v1alpha1.ControllerConfigurationSpec { + fake.getControllerOptionsMutex.Lock() + ret, specificReturn := fake.getControllerOptionsReturnsOnCall[len(fake.getControllerOptionsArgsForCall)] + fake.getControllerOptionsArgsForCall = append(fake.getControllerOptionsArgsForCall, struct { + }{}) + stub := fake.GetControllerOptionsStub + fakeReturns := fake.getControllerOptionsReturns + fake.recordInvocation("GetControllerOptions", []interface{}{}) + fake.getControllerOptionsMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetControllerOptionsCallCount() int { + fake.getControllerOptionsMutex.RLock() + defer fake.getControllerOptionsMutex.RUnlock() + return len(fake.getControllerOptionsArgsForCall) +} + +func (fake *FakeManager) GetControllerOptionsCalls(stub func() v1alpha1.ControllerConfigurationSpec) { + fake.getControllerOptionsMutex.Lock() + defer fake.getControllerOptionsMutex.Unlock() + fake.GetControllerOptionsStub = stub +} + +func (fake *FakeManager) GetControllerOptionsReturns(result1 v1alpha1.ControllerConfigurationSpec) { + fake.getControllerOptionsMutex.Lock() + defer fake.getControllerOptionsMutex.Unlock() + fake.GetControllerOptionsStub = nil + fake.getControllerOptionsReturns = struct { + result1 v1alpha1.ControllerConfigurationSpec + }{result1} +} + +func (fake *FakeManager) GetControllerOptionsReturnsOnCall(i int, result1 v1alpha1.ControllerConfigurationSpec) { + fake.getControllerOptionsMutex.Lock() + defer fake.getControllerOptionsMutex.Unlock() + fake.GetControllerOptionsStub = nil + if fake.getControllerOptionsReturnsOnCall == nil { + fake.getControllerOptionsReturnsOnCall = make(map[int]struct { + result1 v1alpha1.ControllerConfigurationSpec + }) + } + fake.getControllerOptionsReturnsOnCall[i] = struct { + result1 v1alpha1.ControllerConfigurationSpec + }{result1} +} + +func (fake *FakeManager) GetEventRecorderFor(arg1 string) record.EventRecorder { + fake.getEventRecorderForMutex.Lock() + ret, specificReturn := fake.getEventRecorderForReturnsOnCall[len(fake.getEventRecorderForArgsForCall)] + fake.getEventRecorderForArgsForCall = append(fake.getEventRecorderForArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.GetEventRecorderForStub + fakeReturns := fake.getEventRecorderForReturns + fake.recordInvocation("GetEventRecorderFor", []interface{}{arg1}) + fake.getEventRecorderForMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetEventRecorderForCallCount() int { + fake.getEventRecorderForMutex.RLock() + defer fake.getEventRecorderForMutex.RUnlock() + return len(fake.getEventRecorderForArgsForCall) +} + +func (fake *FakeManager) GetEventRecorderForCalls(stub func(string) record.EventRecorder) { + fake.getEventRecorderForMutex.Lock() + defer fake.getEventRecorderForMutex.Unlock() + fake.GetEventRecorderForStub = stub +} + +func (fake *FakeManager) GetEventRecorderForArgsForCall(i int) string { + fake.getEventRecorderForMutex.RLock() + defer fake.getEventRecorderForMutex.RUnlock() + argsForCall := fake.getEventRecorderForArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeManager) GetEventRecorderForReturns(result1 record.EventRecorder) { + fake.getEventRecorderForMutex.Lock() + defer fake.getEventRecorderForMutex.Unlock() + fake.GetEventRecorderForStub = nil + fake.getEventRecorderForReturns = struct { + result1 record.EventRecorder + }{result1} +} + +func (fake *FakeManager) GetEventRecorderForReturnsOnCall(i int, result1 record.EventRecorder) { + fake.getEventRecorderForMutex.Lock() + defer fake.getEventRecorderForMutex.Unlock() + fake.GetEventRecorderForStub = nil + if fake.getEventRecorderForReturnsOnCall == nil { + fake.getEventRecorderForReturnsOnCall = make(map[int]struct { + result1 record.EventRecorder + }) + } + fake.getEventRecorderForReturnsOnCall[i] = struct { + result1 record.EventRecorder + }{result1} +} + +func (fake *FakeManager) GetFieldIndexer() client.FieldIndexer { + fake.getFieldIndexerMutex.Lock() + ret, specificReturn := fake.getFieldIndexerReturnsOnCall[len(fake.getFieldIndexerArgsForCall)] + fake.getFieldIndexerArgsForCall = append(fake.getFieldIndexerArgsForCall, struct { + }{}) + stub := fake.GetFieldIndexerStub + fakeReturns := fake.getFieldIndexerReturns + fake.recordInvocation("GetFieldIndexer", []interface{}{}) + fake.getFieldIndexerMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetFieldIndexerCallCount() int { + fake.getFieldIndexerMutex.RLock() + defer fake.getFieldIndexerMutex.RUnlock() + return len(fake.getFieldIndexerArgsForCall) +} + +func (fake *FakeManager) GetFieldIndexerCalls(stub func() client.FieldIndexer) { + fake.getFieldIndexerMutex.Lock() + defer fake.getFieldIndexerMutex.Unlock() + fake.GetFieldIndexerStub = stub +} + +func (fake *FakeManager) GetFieldIndexerReturns(result1 client.FieldIndexer) { + fake.getFieldIndexerMutex.Lock() + defer fake.getFieldIndexerMutex.Unlock() + fake.GetFieldIndexerStub = nil + fake.getFieldIndexerReturns = struct { + result1 client.FieldIndexer + }{result1} +} + +func (fake *FakeManager) GetFieldIndexerReturnsOnCall(i int, result1 client.FieldIndexer) { + fake.getFieldIndexerMutex.Lock() + defer fake.getFieldIndexerMutex.Unlock() + fake.GetFieldIndexerStub = nil + if fake.getFieldIndexerReturnsOnCall == nil { + fake.getFieldIndexerReturnsOnCall = make(map[int]struct { + result1 client.FieldIndexer + }) + } + fake.getFieldIndexerReturnsOnCall[i] = struct { + result1 client.FieldIndexer + }{result1} +} + +func (fake *FakeManager) GetLogger() logr.Logger { + fake.getLoggerMutex.Lock() + ret, specificReturn := fake.getLoggerReturnsOnCall[len(fake.getLoggerArgsForCall)] + fake.getLoggerArgsForCall = append(fake.getLoggerArgsForCall, struct { + }{}) + stub := fake.GetLoggerStub + fakeReturns := fake.getLoggerReturns + fake.recordInvocation("GetLogger", []interface{}{}) + fake.getLoggerMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetLoggerCallCount() int { + fake.getLoggerMutex.RLock() + defer fake.getLoggerMutex.RUnlock() + return len(fake.getLoggerArgsForCall) +} + +func (fake *FakeManager) GetLoggerCalls(stub func() logr.Logger) { + fake.getLoggerMutex.Lock() + defer fake.getLoggerMutex.Unlock() + fake.GetLoggerStub = stub +} + +func (fake *FakeManager) GetLoggerReturns(result1 logr.Logger) { + fake.getLoggerMutex.Lock() + defer fake.getLoggerMutex.Unlock() + fake.GetLoggerStub = nil + fake.getLoggerReturns = struct { + result1 logr.Logger + }{result1} +} + +func (fake *FakeManager) GetLoggerReturnsOnCall(i int, result1 logr.Logger) { + fake.getLoggerMutex.Lock() + defer fake.getLoggerMutex.Unlock() + fake.GetLoggerStub = nil + if fake.getLoggerReturnsOnCall == nil { + fake.getLoggerReturnsOnCall = make(map[int]struct { + result1 logr.Logger + }) + } + fake.getLoggerReturnsOnCall[i] = struct { + result1 logr.Logger + }{result1} +} + +func (fake *FakeManager) GetRESTMapper() meta.RESTMapper { + fake.getRESTMapperMutex.Lock() + ret, specificReturn := fake.getRESTMapperReturnsOnCall[len(fake.getRESTMapperArgsForCall)] + fake.getRESTMapperArgsForCall = append(fake.getRESTMapperArgsForCall, struct { + }{}) + stub := fake.GetRESTMapperStub + fakeReturns := fake.getRESTMapperReturns + fake.recordInvocation("GetRESTMapper", []interface{}{}) + fake.getRESTMapperMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetRESTMapperCallCount() int { + fake.getRESTMapperMutex.RLock() + defer fake.getRESTMapperMutex.RUnlock() + return len(fake.getRESTMapperArgsForCall) +} + +func (fake *FakeManager) GetRESTMapperCalls(stub func() meta.RESTMapper) { + fake.getRESTMapperMutex.Lock() + defer fake.getRESTMapperMutex.Unlock() + fake.GetRESTMapperStub = stub +} + +func (fake *FakeManager) GetRESTMapperReturns(result1 meta.RESTMapper) { + fake.getRESTMapperMutex.Lock() + defer fake.getRESTMapperMutex.Unlock() + fake.GetRESTMapperStub = nil + fake.getRESTMapperReturns = struct { + result1 meta.RESTMapper + }{result1} +} + +func (fake *FakeManager) GetRESTMapperReturnsOnCall(i int, result1 meta.RESTMapper) { + fake.getRESTMapperMutex.Lock() + defer fake.getRESTMapperMutex.Unlock() + fake.GetRESTMapperStub = nil + if fake.getRESTMapperReturnsOnCall == nil { + fake.getRESTMapperReturnsOnCall = make(map[int]struct { + result1 meta.RESTMapper + }) + } + fake.getRESTMapperReturnsOnCall[i] = struct { + result1 meta.RESTMapper + }{result1} +} + +func (fake *FakeManager) GetScheme() *runtime.Scheme { + fake.getSchemeMutex.Lock() + ret, specificReturn := fake.getSchemeReturnsOnCall[len(fake.getSchemeArgsForCall)] + fake.getSchemeArgsForCall = append(fake.getSchemeArgsForCall, struct { + }{}) + stub := fake.GetSchemeStub + fakeReturns := fake.getSchemeReturns + fake.recordInvocation("GetScheme", []interface{}{}) + fake.getSchemeMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetSchemeCallCount() int { + fake.getSchemeMutex.RLock() + defer fake.getSchemeMutex.RUnlock() + return len(fake.getSchemeArgsForCall) +} + +func (fake *FakeManager) GetSchemeCalls(stub func() *runtime.Scheme) { + fake.getSchemeMutex.Lock() + defer fake.getSchemeMutex.Unlock() + fake.GetSchemeStub = stub +} + +func (fake *FakeManager) GetSchemeReturns(result1 *runtime.Scheme) { + fake.getSchemeMutex.Lock() + defer fake.getSchemeMutex.Unlock() + fake.GetSchemeStub = nil + fake.getSchemeReturns = struct { + result1 *runtime.Scheme + }{result1} +} + +func (fake *FakeManager) GetSchemeReturnsOnCall(i int, result1 *runtime.Scheme) { + fake.getSchemeMutex.Lock() + defer fake.getSchemeMutex.Unlock() + fake.GetSchemeStub = nil + if fake.getSchemeReturnsOnCall == nil { + fake.getSchemeReturnsOnCall = make(map[int]struct { + result1 *runtime.Scheme + }) + } + fake.getSchemeReturnsOnCall[i] = struct { + result1 *runtime.Scheme + }{result1} +} + +func (fake *FakeManager) GetWebhookServer() *webhook.Server { + fake.getWebhookServerMutex.Lock() + ret, specificReturn := fake.getWebhookServerReturnsOnCall[len(fake.getWebhookServerArgsForCall)] + fake.getWebhookServerArgsForCall = append(fake.getWebhookServerArgsForCall, struct { + }{}) + stub := fake.GetWebhookServerStub + fakeReturns := fake.getWebhookServerReturns + fake.recordInvocation("GetWebhookServer", []interface{}{}) + fake.getWebhookServerMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) GetWebhookServerCallCount() int { + fake.getWebhookServerMutex.RLock() + defer fake.getWebhookServerMutex.RUnlock() + return len(fake.getWebhookServerArgsForCall) +} + +func (fake *FakeManager) GetWebhookServerCalls(stub func() *webhook.Server) { + fake.getWebhookServerMutex.Lock() + defer fake.getWebhookServerMutex.Unlock() + fake.GetWebhookServerStub = stub +} + +func (fake *FakeManager) GetWebhookServerReturns(result1 *webhook.Server) { + fake.getWebhookServerMutex.Lock() + defer fake.getWebhookServerMutex.Unlock() + fake.GetWebhookServerStub = nil + fake.getWebhookServerReturns = struct { + result1 *webhook.Server + }{result1} +} + +func (fake *FakeManager) GetWebhookServerReturnsOnCall(i int, result1 *webhook.Server) { + fake.getWebhookServerMutex.Lock() + defer fake.getWebhookServerMutex.Unlock() + fake.GetWebhookServerStub = nil + if fake.getWebhookServerReturnsOnCall == nil { + fake.getWebhookServerReturnsOnCall = make(map[int]struct { + result1 *webhook.Server + }) + } + fake.getWebhookServerReturnsOnCall[i] = struct { + result1 *webhook.Server + }{result1} +} + +func (fake *FakeManager) SetFields(arg1 interface{}) error { + fake.setFieldsMutex.Lock() + ret, specificReturn := fake.setFieldsReturnsOnCall[len(fake.setFieldsArgsForCall)] + fake.setFieldsArgsForCall = append(fake.setFieldsArgsForCall, struct { + arg1 interface{} + }{arg1}) + stub := fake.SetFieldsStub + fakeReturns := fake.setFieldsReturns + fake.recordInvocation("SetFields", []interface{}{arg1}) + fake.setFieldsMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) SetFieldsCallCount() int { + fake.setFieldsMutex.RLock() + defer fake.setFieldsMutex.RUnlock() + return len(fake.setFieldsArgsForCall) +} + +func (fake *FakeManager) SetFieldsCalls(stub func(interface{}) error) { + fake.setFieldsMutex.Lock() + defer fake.setFieldsMutex.Unlock() + fake.SetFieldsStub = stub +} + +func (fake *FakeManager) SetFieldsArgsForCall(i int) interface{} { + fake.setFieldsMutex.RLock() + defer fake.setFieldsMutex.RUnlock() + argsForCall := fake.setFieldsArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeManager) SetFieldsReturns(result1 error) { + fake.setFieldsMutex.Lock() + defer fake.setFieldsMutex.Unlock() + fake.SetFieldsStub = nil + fake.setFieldsReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) SetFieldsReturnsOnCall(i int, result1 error) { + fake.setFieldsMutex.Lock() + defer fake.setFieldsMutex.Unlock() + fake.SetFieldsStub = nil + if fake.setFieldsReturnsOnCall == nil { + fake.setFieldsReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.setFieldsReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) Start(arg1 context.Context) error { + fake.startMutex.Lock() + ret, specificReturn := fake.startReturnsOnCall[len(fake.startArgsForCall)] + fake.startArgsForCall = append(fake.startArgsForCall, struct { + arg1 context.Context + }{arg1}) + stub := fake.StartStub + fakeReturns := fake.startReturns + fake.recordInvocation("Start", []interface{}{arg1}) + fake.startMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeManager) StartCallCount() int { + fake.startMutex.RLock() + defer fake.startMutex.RUnlock() + return len(fake.startArgsForCall) +} + +func (fake *FakeManager) StartCalls(stub func(context.Context) error) { + fake.startMutex.Lock() + defer fake.startMutex.Unlock() + fake.StartStub = stub +} + +func (fake *FakeManager) StartArgsForCall(i int) context.Context { + fake.startMutex.RLock() + defer fake.startMutex.RUnlock() + argsForCall := fake.startArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeManager) StartReturns(result1 error) { + fake.startMutex.Lock() + defer fake.startMutex.Unlock() + fake.StartStub = nil + fake.startReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) StartReturnsOnCall(i int, result1 error) { + fake.startMutex.Lock() + defer fake.startMutex.Unlock() + fake.StartStub = nil + if fake.startReturnsOnCall == nil { + fake.startReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.startReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeManager) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.addMutex.RLock() + defer fake.addMutex.RUnlock() + fake.addHealthzCheckMutex.RLock() + defer fake.addHealthzCheckMutex.RUnlock() + fake.addMetricsExtraHandlerMutex.RLock() + defer fake.addMetricsExtraHandlerMutex.RUnlock() + fake.addReadyzCheckMutex.RLock() + defer fake.addReadyzCheckMutex.RUnlock() + fake.electedMutex.RLock() + defer fake.electedMutex.RUnlock() + fake.getAPIReaderMutex.RLock() + defer fake.getAPIReaderMutex.RUnlock() + fake.getCacheMutex.RLock() + defer fake.getCacheMutex.RUnlock() + fake.getClientMutex.RLock() + defer fake.getClientMutex.RUnlock() + fake.getConfigMutex.RLock() + defer fake.getConfigMutex.RUnlock() + fake.getControllerOptionsMutex.RLock() + defer fake.getControllerOptionsMutex.RUnlock() + fake.getEventRecorderForMutex.RLock() + defer fake.getEventRecorderForMutex.RUnlock() + fake.getFieldIndexerMutex.RLock() + defer fake.getFieldIndexerMutex.RUnlock() + fake.getLoggerMutex.RLock() + defer fake.getLoggerMutex.RUnlock() + fake.getRESTMapperMutex.RLock() + defer fake.getRESTMapperMutex.RUnlock() + fake.getSchemeMutex.RLock() + defer fake.getSchemeMutex.RUnlock() + fake.getWebhookServerMutex.RLock() + defer fake.getWebhookServerMutex.RUnlock() + fake.setFieldsMutex.RLock() + defer fake.setFieldsMutex.RUnlock() + fake.startMutex.RLock() + defer fake.startMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeManager) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ manager.Manager = new(FakeManager) diff --git a/pkg/sdk/service_controller.go b/internal/manager/predicate/service.go similarity index 51% rename from pkg/sdk/service_controller.go rename to internal/manager/predicate/service.go index 01a5936e6c..eed0e9e2d2 100644 --- a/pkg/sdk/service_controller.go +++ b/internal/manager/predicate/service.go @@ -1,27 +1,12 @@ -package sdk +package predicate import ( - "context" - apiv1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" - ctlr "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -type serviceReconciler struct { - client.Client - scheme *runtime.Scheme - impl ServiceImpl -} - // ServicePortsChangedPredicate implements an update predicate function based on the Ports of a Service. // This predicate will skip update events that have no change in the Service Ports and TargetPorts. type ServicePortsChangedPredicate struct { @@ -78,46 +63,3 @@ func (ServicePortsChangedPredicate) Update(e event.UpdateEvent) bool { return len(newPortSet) > 0 } - -// RegisterServiceController registers the ServiceController in the manager. -func RegisterServiceController(mgr manager.Manager, impl ServiceImpl) error { - r := &serviceReconciler{ - Client: mgr.GetClient(), - scheme: mgr.GetScheme(), - impl: impl, - } - - return ctlr.NewControllerManagedBy(mgr). - For(&apiv1.Service{}). - WithEventFilter(ServicePortsChangedPredicate{}). - Complete(r) -} - -func (r *serviceReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - log := log.FromContext(ctx).WithValues("service", req.NamespacedName) - - log.V(3).Info("Reconciling Service") - - found := true - var svc apiv1.Service - err := r.Get(ctx, req.NamespacedName, &svc) - if err != nil { - if !apierrors.IsNotFound(err) { - log.Error(err, "Failed to get Service") - return reconcile.Result{}, err - } - found = false - } - - if !found { - log.V(3).Info("Removing Service") - - r.impl.Remove(req.NamespacedName) - return reconcile.Result{}, nil - } - - log.V(3).Info("Upserting Service") - - r.impl.Upsert(&svc) - return reconcile.Result{}, nil -} diff --git a/pkg/sdk/service_controller_test.go b/internal/manager/predicate/service_test.go similarity index 92% rename from pkg/sdk/service_controller_test.go rename to internal/manager/predicate/service_test.go index baef767b5a..007905b1a2 100644 --- a/pkg/sdk/service_controller_test.go +++ b/internal/manager/predicate/service_test.go @@ -1,4 +1,4 @@ -package sdk_test +package predicate import ( "testing" @@ -7,8 +7,6 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" - - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" ) func TestServicePortsChangedPredicate_Update(t *testing.T) { @@ -223,10 +221,10 @@ func TestServicePortsChangedPredicate_Update(t *testing.T) { }, } - predicate := sdk.ServicePortsChangedPredicate{} + p := ServicePortsChangedPredicate{} for _, tc := range testcases { - update := predicate.Update(event.UpdateEvent{ + update := p.Update(event.UpdateEvent{ ObjectOld: tc.objectOld, ObjectNew: tc.objectNew, }) @@ -238,17 +236,17 @@ func TestServicePortsChangedPredicate_Update(t *testing.T) { } func TestServicePortsChangedPredicate(t *testing.T) { - predicate := sdk.ServicePortsChangedPredicate{} + p := ServicePortsChangedPredicate{} - if !predicate.Delete(event.DeleteEvent{Object: &v1.Service{}}) { + if !p.Delete(event.DeleteEvent{Object: &v1.Service{}}) { t.Errorf("ServicePortsChangedPredicate.Delete() returned false; expected true") } - if !predicate.Create(event.CreateEvent{Object: &v1.Service{}}) { + if !p.Create(event.CreateEvent{Object: &v1.Service{}}) { t.Errorf("ServicePortsChangedPredicate.Create() returned false; expected true") } - if !predicate.Generic(event.GenericEvent{Object: &v1.Service{}}) { + if !p.Generic(event.GenericEvent{Object: &v1.Service{}}) { t.Errorf("ServicePortsChangedPredicate.Generic() returned false; expected true") } } diff --git a/internal/reconciler/getter.go b/internal/reconciler/getter.go new file mode 100644 index 0000000000..74667fbd93 --- /dev/null +++ b/internal/reconciler/getter.go @@ -0,0 +1,16 @@ +package reconciler + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . Getter + +// Getter gets a resource from the k8s API. +// It allows us to mock the client.Reader.Get method. +type Getter interface { + // Get is from client.Reader. + Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error +} diff --git a/internal/reconciler/implementation.go b/internal/reconciler/implementation.go new file mode 100644 index 0000000000..49783386dd --- /dev/null +++ b/internal/reconciler/implementation.go @@ -0,0 +1,111 @@ +package reconciler + +import ( + "context" + "fmt" + "reflect" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" +) + +// NamespacedNameFilterFunc is a function that returns true if the resource should be processed by the reconciler. +// If the function returns false, the reconciler will log the returned string. +type NamespacedNameFilterFunc func(nsname types.NamespacedName) (bool, string) + +// Config contains the configuration for the Implementation. +type Config struct { + // Getter gets a resource from the k8s API. + Getter Getter + // ObjectType is the type of the resource that the reconciler will reconcile. + ObjectType client.Object + // EventCh is the channel where the reconciler will send events. + EventCh chan<- interface{} + // NamespacedNameFilter filters resources the controller will process. Can be nil. + NamespacedNameFilter NamespacedNameFilterFunc +} + +// Implementation is a reconciler for Kubernetes resources. +// It implements the reconcile.Reconciler interface. +// A successful reconciliation of a resource has the two possible outcomes: +// (1) If the resource is deleted, the Implementation will send a DeleteEvent to the event channel. +// (2) If the resource is upserted (created or updated), the Implementation will send an UpsertEvent +// to the event channel. +type Implementation struct { + cfg Config +} + +var _ reconcile.Reconciler = &Implementation{} + +// NewImplementation creates a new Implementation. +func NewImplementation(cfg Config) *Implementation { + return &Implementation{ + cfg: cfg, + } +} + +func newObject(objectType client.Object) client.Object { + // without Elem(), t will be a pointer to the type. For example, *v1beta1.Gateway, not v1beta1.Gateway + t := reflect.TypeOf(objectType).Elem() + + // We could've used objectType.DeepCopyObject() here, but it's a bit slower confirmed by benchmarks. + + return reflect.New(t).Interface().(client.Object) +} + +// Reconcile implements the reconcile.Reconciler Reconcile method. +func (r *Implementation) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { + logger := log.FromContext(ctx) + // The controller runtime has set the logger with the group, kind, namespace and name of the resource, + // and a few other key/value pairs. So we don't need to set them here. + + logger.Info("Reconciling the resource") + + found := true + obj := newObject(r.cfg.ObjectType) + err := r.cfg.Getter.Get(ctx, req.NamespacedName, obj) + if err != nil { + if !apierrors.IsNotFound(err) { + logger.Error(err, "Failed to get the resource") + return reconcile.Result{}, err + } + found = false + } + + if r.cfg.NamespacedNameFilter != nil { + if allow, msg := r.cfg.NamespacedNameFilter(req.NamespacedName); !allow { + logger.Info(msg) + return reconcile.Result{}, nil + } + } + + var e interface{} + var operation string + + if !found { + e = &events.DeleteEvent{ + Type: r.cfg.ObjectType, + NamespacedName: req.NamespacedName, + } + operation = "deleted" + } else { + e = &events.UpsertEvent{ + Resource: obj, + } + operation = "upserted" + } + + select { + case <-ctx.Done(): + logger.Info(fmt.Sprintf("The resource was not %s because the context was canceled", operation)) + case r.cfg.EventCh <- e: + logger.Info(fmt.Sprintf("The resource was %s", operation)) + } + + return reconcile.Result{}, nil +} diff --git a/internal/reconciler/implementation_test.go b/internal/reconciler/implementation_test.go new file mode 100644 index 0000000000..a8e6d6940a --- /dev/null +++ b/internal/reconciler/implementation_test.go @@ -0,0 +1,244 @@ +package reconciler_test + +import ( + "context" + "errors" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/gateway-api/apis/v1beta1" + + "github.com/nginxinc/nginx-kubernetes-gateway/internal/reconciler/reconcilerfakes" + + "github.com/nginxinc/nginx-kubernetes-gateway/internal/events" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/reconciler" +) + +type getFunc func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error + +type result struct { + err error + reconcileResult reconcile.Result +} + +var _ = Describe("Reconciler", func() { + var ( + rec *reconciler.Implementation + fakeGetter *reconcilerfakes.FakeGetter + eventCh chan interface{} + + hr1NsName = types.NamespacedName{ + Namespace: "test", + Name: "hr-1", + } + + hr1 = &v1beta1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: hr1NsName.Namespace, + Name: hr1NsName.Name, + }, + } + + hr2NsName = types.NamespacedName{ + Namespace: "test", + Name: "hr-2", + } + + hr2 = &v1beta1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: hr2NsName.Namespace, + Name: hr2NsName.Name, + }, + } + ) + + getReturnsHRForHR := func(hr *v1beta1.HTTPRoute) getFunc { + return func( + ctx context.Context, + nsname types.NamespacedName, + object client.Object, + option ...client.GetOption, + ) error { + Expect(object).To(BeAssignableToTypeOf(&v1beta1.HTTPRoute{})) + Expect(nsname).To(Equal(client.ObjectKeyFromObject(hr))) + + hr.DeepCopyInto(object.(*v1beta1.HTTPRoute)) + + return nil + } + } + + getReturnsNotFoundErrorForHR := func(hr *v1beta1.HTTPRoute) getFunc { + return func( + ctx context.Context, + nsname types.NamespacedName, + object client.Object, + option ...client.GetOption, + ) error { + Expect(object).To(BeAssignableToTypeOf(&v1beta1.HTTPRoute{})) + Expect(nsname).To(Equal(client.ObjectKeyFromObject(hr))) + + return apierrors.NewNotFound(schema.GroupResource{}, "not found") + } + } + + startReconcilingWithContext := func(ctx context.Context, nsname types.NamespacedName) <-chan result { + resultCh := make(chan result) + + go func() { + defer GinkgoRecover() + + res, err := rec.Reconcile(ctx, reconcile.Request{NamespacedName: nsname}) + resultCh <- result{err: err, reconcileResult: res} + + close(resultCh) + }() + + return resultCh + } + + startReconciling := func(nsname types.NamespacedName) <-chan result { + return startReconcilingWithContext(context.Background(), nsname) + } + + BeforeEach(func() { + fakeGetter = &reconcilerfakes.FakeGetter{} + eventCh = make(chan interface{}) + }) + + Describe("Normal cases", func() { + When("Reconciler doesn't have a filter", func() { + BeforeEach(func() { + rec = reconciler.NewImplementation(reconciler.Config{ + Getter: fakeGetter, + ObjectType: &v1beta1.HTTPRoute{}, + EventCh: eventCh, + }) + }) + + It("should upsert HTTPRoute", func() { + fakeGetter.GetCalls(getReturnsHRForHR(hr1)) + + resultCh := startReconciling(hr1NsName) + + Eventually(eventCh).Should(Receive(Equal(&events.UpsertEvent{Resource: hr1}))) + Eventually(resultCh).Should(Receive(Equal(result{err: nil, reconcileResult: reconcile.Result{}}))) + }) + + It("should delete HTTPRoute", func() { + fakeGetter.GetCalls(getReturnsNotFoundErrorForHR(hr1)) + + resultCh := startReconciling(hr1NsName) + + Eventually(eventCh).Should(Receive(Equal(&events.DeleteEvent{ + NamespacedName: hr1NsName, + Type: &v1beta1.HTTPRoute{}, + }))) + Eventually(resultCh).Should(Receive(Equal(result{err: nil, reconcileResult: reconcile.Result{}}))) + }) + }) + + When("Reconciler has a NamespacedNameFilter", func() { + BeforeEach(func() { + filter := func(nsname types.NamespacedName) (bool, string) { + if nsname != hr1NsName { + return false, "ignore" + } + return true, "" + } + + rec = reconciler.NewImplementation(reconciler.Config{ + Getter: fakeGetter, + ObjectType: &v1beta1.HTTPRoute{}, + EventCh: eventCh, + NamespacedNameFilter: filter, + }) + }) + + When("HTTPRoute is not ignored", func() { + It("should upsert HTTPRoute", func() { + fakeGetter.GetCalls(getReturnsHRForHR(hr1)) + + resultCh := startReconciling(hr1NsName) + + Eventually(eventCh).Should(Receive(Equal(&events.UpsertEvent{Resource: hr1}))) + Eventually(resultCh).Should(Receive(Equal(result{err: nil, reconcileResult: reconcile.Result{}}))) + }) + + It("should delete HTTPRoute", func() { + fakeGetter.GetCalls(getReturnsNotFoundErrorForHR(hr1)) + + resultCh := startReconciling(hr1NsName) + + Eventually(eventCh).Should(Receive(Equal(&events.DeleteEvent{ + NamespacedName: hr1NsName, + Type: &v1beta1.HTTPRoute{}, + }))) + Eventually(resultCh).Should(Receive(Equal(result{err: nil, reconcileResult: reconcile.Result{}}))) + }) + }) + + When("HTTPRoute is ignored", func() { + It("should not upsert HTTPRoute", func() { + fakeGetter.GetCalls(getReturnsHRForHR(hr2)) + + resultCh := startReconciling(hr2NsName) + + Consistently(eventCh).ShouldNot(Receive()) + Eventually(resultCh).Should(Receive(Equal(result{err: nil, reconcileResult: reconcile.Result{}}))) + }) + + It("should not delete HTTPRoute", func() { + fakeGetter.GetCalls(getReturnsNotFoundErrorForHR(hr2)) + + resultCh := startReconciling(hr2NsName) + + Consistently(eventCh).ShouldNot(Receive()) + Eventually(resultCh).Should(Receive(Equal(result{err: nil, reconcileResult: reconcile.Result{}}))) + }) + }) + }) + }) + + Describe("Edge cases", func() { + BeforeEach(func() { + rec = reconciler.NewImplementation(reconciler.Config{ + Getter: fakeGetter, + ObjectType: &v1beta1.HTTPRoute{}, + EventCh: eventCh, + }) + }) + + It("should not reconcile when Getter returns error", func() { + getError := errors.New("get error") + fakeGetter.GetReturns(getError) + + resultCh := startReconciling(hr1NsName) + + Consistently(eventCh).ShouldNot(Receive()) + Eventually(resultCh).Should(Receive(Equal(result{err: getError, reconcileResult: reconcile.Result{}}))) + }) + + DescribeTable("Reconciler should not block when ctx is done", + func(get getFunc, nsname types.NamespacedName) { + fakeGetter.GetCalls(get) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + resultCh := startReconcilingWithContext(ctx, nsname) + + Consistently(eventCh).ShouldNot(Receive()) + Expect(resultCh).To(Receive(Equal(result{err: nil, reconcileResult: reconcile.Result{}}))) + }, + Entry("Upserting HTTPRoute", getReturnsHRForHR(hr1), hr1NsName), + Entry("Deleting HTTPRoute", getReturnsNotFoundErrorForHR(hr1), hr1NsName), + ) + }) +}) diff --git a/internal/reconciler/reconciler_suite_test.go b/internal/reconciler/reconciler_suite_test.go new file mode 100644 index 0000000000..caad3bda4f --- /dev/null +++ b/internal/reconciler/reconciler_suite_test.go @@ -0,0 +1,13 @@ +package reconciler_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Reconciler Suite") +} diff --git a/internal/reconciler/reconcilerfakes/fake_getter.go b/internal/reconciler/reconcilerfakes/fake_getter.go new file mode 100644 index 0000000000..041bbd86a5 --- /dev/null +++ b/internal/reconciler/reconcilerfakes/fake_getter.go @@ -0,0 +1,120 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package reconcilerfakes + +import ( + "context" + "sync" + + "github.com/nginxinc/nginx-kubernetes-gateway/internal/reconciler" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type FakeGetter struct { + GetStub func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error + getMutex sync.RWMutex + getArgsForCall []struct { + arg1 context.Context + arg2 types.NamespacedName + arg3 client.Object + arg4 []client.GetOption + } + getReturns struct { + result1 error + } + getReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeGetter) Get(arg1 context.Context, arg2 types.NamespacedName, arg3 client.Object, arg4 ...client.GetOption) error { + fake.getMutex.Lock() + ret, specificReturn := fake.getReturnsOnCall[len(fake.getArgsForCall)] + fake.getArgsForCall = append(fake.getArgsForCall, struct { + arg1 context.Context + arg2 types.NamespacedName + arg3 client.Object + arg4 []client.GetOption + }{arg1, arg2, arg3, arg4}) + stub := fake.GetStub + fakeReturns := fake.getReturns + fake.recordInvocation("Get", []interface{}{arg1, arg2, arg3, arg4}) + fake.getMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4...) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeGetter) GetCallCount() int { + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + return len(fake.getArgsForCall) +} + +func (fake *FakeGetter) GetCalls(stub func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = stub +} + +func (fake *FakeGetter) GetArgsForCall(i int) (context.Context, types.NamespacedName, client.Object, []client.GetOption) { + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + argsForCall := fake.getArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeGetter) GetReturns(result1 error) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = nil + fake.getReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeGetter) GetReturnsOnCall(i int, result1 error) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = nil + if fake.getReturnsOnCall == nil { + fake.getReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.getReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeGetter) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeGetter) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ reconciler.Getter = new(FakeGetter) diff --git a/internal/state/change_processor_test.go b/internal/state/change_processor_test.go index 45da87975a..bdba79cd9f 100644 --- a/internal/state/change_processor_test.go +++ b/internal/state/change_processor_test.go @@ -15,11 +15,11 @@ import ( "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/nginxinc/nginx-kubernetes-gateway/internal/helpers" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/index" "github.com/nginxinc/nginx-kubernetes-gateway/internal/state" "github.com/nginxinc/nginx-kubernetes-gateway/internal/state/relationship" "github.com/nginxinc/nginx-kubernetes-gateway/internal/state/relationship/relationshipfakes" "github.com/nginxinc/nginx-kubernetes-gateway/internal/state/statefakes" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" ) const ( @@ -1024,7 +1024,7 @@ var _ = Describe("ChangeProcessor", func() { ObjectMeta: metav1.ObjectMeta{ Namespace: "test", Name: name, - Labels: map[string]string{sdk.KubernetesServiceNameLabel: svcName}, + Labels: map[string]string{index.KubernetesServiceNameLabel: svcName}, }, } } diff --git a/internal/state/relationship/capturer.go b/internal/state/relationship/capturer.go index 0aab716bf0..f643ae4848 100644 --- a/internal/state/relationship/capturer.go +++ b/internal/state/relationship/capturer.go @@ -7,7 +7,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/gateway-api/apis/v1beta1" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/index" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . Capturer @@ -56,7 +56,7 @@ func (c *CapturerImpl) Capture(obj client.Object) { case *v1beta1.HTTPRoute: c.upsertForRoute(o) case *discoveryV1.EndpointSlice: - svcName := sdk.GetServiceNameFromEndpointSlice(o) + svcName := index.GetServiceNameFromEndpointSlice(o) if svcName != "" { c.endpointSliceOwners[client.ObjectKeyFromObject(o)] = types.NamespacedName{ Namespace: o.Namespace, diff --git a/internal/state/relationship/capturer_test.go b/internal/state/relationship/capturer_test.go index 52aee67376..ecb4b32849 100644 --- a/internal/state/relationship/capturer_test.go +++ b/internal/state/relationship/capturer_test.go @@ -10,8 +10,8 @@ import ( "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/nginxinc/nginx-kubernetes-gateway/internal/helpers" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/index" "github.com/nginxinc/nginx-kubernetes-gateway/internal/state/relationship" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" ) func createBackendRefs(backendNames ...v1beta1.ObjectName) []v1beta1.HTTPBackendRef { @@ -234,7 +234,7 @@ var _ = Describe("Capturer", func() { ObjectMeta: metav1.ObjectMeta{ Namespace: "test", Name: "es1", - Labels: map[string]string{sdk.KubernetesServiceNameLabel: "svc1"}, + Labels: map[string]string{index.KubernetesServiceNameLabel: "svc1"}, }, } @@ -242,7 +242,7 @@ var _ = Describe("Capturer", func() { ObjectMeta: metav1.ObjectMeta{ Namespace: "test", Name: "es2", - Labels: map[string]string{sdk.KubernetesServiceNameLabel: "svc1"}, + Labels: map[string]string{index.KubernetesServiceNameLabel: "svc1"}, }, } @@ -290,7 +290,7 @@ var _ = Describe("Capturer", func() { When("endpoint slice service owner changes to an unrelated service owner", func() { It("removes the endpoint slice relationship", func() { updatedSlice1 := slice1.DeepCopy() - updatedSlice1.Labels[sdk.KubernetesServiceNameLabel] = "unrelated-svc" + updatedSlice1.Labels[index.KubernetesServiceNameLabel] = "unrelated-svc" capturer.Capture(updatedSlice1) diff --git a/internal/state/resolver/resolver.go b/internal/state/resolver/resolver.go index ec3b260c20..bd1d733ff3 100644 --- a/internal/state/resolver/resolver.go +++ b/internal/state/resolver/resolver.go @@ -9,7 +9,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk" + "github.com/nginxinc/nginx-kubernetes-gateway/internal/manager/index" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . ServiceResolver @@ -51,7 +51,7 @@ func (e *ServiceResolverImpl) Resolve(ctx context.Context, svc *v1.Service, port err := e.client.List( ctx, &endpointSliceList, - client.MatchingFields{sdk.KubernetesServiceNameIndexField: svc.Name}, + client.MatchingFields{index.KubernetesServiceNameIndexField: svc.Name}, client.InNamespace(svc.Namespace), ) @@ -116,7 +116,7 @@ func getServicePort(svc *v1.Service, port int32) (v1.ServicePort, error) { } } - return v1.ServicePort{}, fmt.Errorf("no matching port for Service %s and port %d", svc, port) + return v1.ServicePort{}, fmt.Errorf("no matching port for Service %s and port %d", svc.Name, port) } // getDefaultPort returns the default port for a ServicePort. diff --git a/pkg/sdk/endpointslice_controller.go b/pkg/sdk/endpointslice_controller.go deleted file mode 100644 index 7a9a6b320d..0000000000 --- a/pkg/sdk/endpointslice_controller.go +++ /dev/null @@ -1,115 +0,0 @@ -package sdk - -import ( - "context" - "fmt" - "time" - - discoveryV1 "k8s.io/api/discovery/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctlr "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -const ( - // KubernetesServiceNameIndexField is the name of the Index Field used to index EndpointSlices by their service - // owners. - KubernetesServiceNameIndexField = "k8sServiceName" - // KubernetesServiceNameLabel is the label used to identify the Kubernetes service name on an EndpointSlice. - KubernetesServiceNameLabel = "kubernetes.io/service-name" - // addIndexFieldTimeout is the timeout used for adding an Index Field to the EndpointSlice cache. - addIndexFieldTimeout = 2 * time.Minute -) - -type endpointSliceReconciler struct { - client.Client - scheme *runtime.Scheme - impl EndpointSliceImpl -} - -// ServiceNameIndexFunc is a client.IndexerFunc that parses a Kubernetes object and returns the value of the -// Kubernetes service-name label. -// Used to index EndpointSlices by their service owners. -func ServiceNameIndexFunc(obj client.Object) []string { - slice, ok := obj.(*discoveryV1.EndpointSlice) - if !ok { - panic(fmt.Sprintf("expected an EndpointSlice; got %T", obj)) - } - - name := GetServiceNameFromEndpointSlice(slice) - if name == "" { - return nil - } - - return []string{name} -} - -// GetServiceNameFromEndpointSlice returns the value of the Kubernetes service-name label from an EndpointSlice. -func GetServiceNameFromEndpointSlice(slice *discoveryV1.EndpointSlice) string { - if slice.Labels == nil { - return "" - } - - return slice.Labels[KubernetesServiceNameLabel] -} - -// RegisterEndpointSliceController registers the EndpointSliceController in the manager. -func RegisterEndpointSliceController(ctx context.Context, mgr manager.Manager, impl EndpointSliceImpl) error { - r := &endpointSliceReconciler{ - Client: mgr.GetClient(), - scheme: mgr.GetScheme(), - impl: impl, - } - - ctx, cancel := context.WithTimeout(ctx, addIndexFieldTimeout) - defer cancel() - - err := mgr.GetFieldIndexer().IndexField( - ctx, - &discoveryV1.EndpointSlice{}, - KubernetesServiceNameIndexField, - ServiceNameIndexFunc, - ) - if err != nil { - return fmt.Errorf("failed to add service name index for EndpointSlices: %w", err) - } - - return ctlr.NewControllerManagedBy(mgr). - For(&discoveryV1.EndpointSlice{}). - WithEventFilter(predicate.GenerationChangedPredicate{}). - Complete(r) -} - -func (r *endpointSliceReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - log := log.FromContext(ctx).WithValues("endpointslice", req.NamespacedName) - - log.V(3).Info("Reconciling EndpointSlice") - - found := true - var endpSlice discoveryV1.EndpointSlice - err := r.Get(ctx, req.NamespacedName, &endpSlice) - if err != nil { - if !apierrors.IsNotFound(err) { - log.Error(err, "Failed to get EndpointSlice") - return reconcile.Result{}, err - } - found = false - } - - if !found { - log.V(3).Info("Removing EndpointSlice") - - r.impl.Remove(req.NamespacedName) - return reconcile.Result{}, nil - } - - log.V(3).Info("Upserting EndpointSlice") - - r.impl.Upsert(&endpSlice) - return reconcile.Result{}, nil -} diff --git a/pkg/sdk/gateway_controller.go b/pkg/sdk/gateway_controller.go deleted file mode 100644 index a6c21f11dc..0000000000 --- a/pkg/sdk/gateway_controller.go +++ /dev/null @@ -1,56 +0,0 @@ -package sdk - -import ( - "context" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctlr "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -type gatewayReconciler struct { - client.Client - scheme *runtime.Scheme - impl GatewayImpl -} - -func RegisterGatewayController(mgr manager.Manager, impl GatewayImpl) error { - r := &gatewayReconciler{ - Client: mgr.GetClient(), - scheme: mgr.GetScheme(), - impl: impl, - } - - return ctlr.NewControllerManagedBy(mgr). - For(&v1beta1.Gateway{}). - Complete(r) -} - -func (r *gatewayReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - log := log.FromContext(ctx).WithValues("gateway", req.Name) - log.V(3).Info("Reconciling Gateway") - - found := true - var gw v1beta1.Gateway - err := r.Get(ctx, req.NamespacedName, &gw) - if err != nil { - if !apierrors.IsNotFound(err) { - log.Error(err, "Failed to get Gateway") - return reconcile.Result{}, err - } - found = false - } - - if !found { - r.impl.Remove(req.NamespacedName) - return reconcile.Result{}, nil - } - - r.impl.Upsert(&gw) - return reconcile.Result{}, nil -} diff --git a/pkg/sdk/gatewayclass_controller.go b/pkg/sdk/gatewayclass_controller.go deleted file mode 100644 index d4a211c04e..0000000000 --- a/pkg/sdk/gatewayclass_controller.go +++ /dev/null @@ -1,56 +0,0 @@ -package sdk - -import ( - "golang.org/x/net/context" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -type gatewayClassReconciler struct { - client.Client - scheme *runtime.Scheme - impl GatewayClassImpl -} - -func RegisterGatewayClassController(mgr manager.Manager, impl GatewayClassImpl) error { - r := &gatewayClassReconciler{ - impl: impl, - Client: mgr.GetClient(), - scheme: mgr.GetScheme(), - } - - return ctrl.NewControllerManagedBy(mgr). - For(&v1beta1.GatewayClass{}). - Complete(r) -} - -func (r *gatewayClassReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - log := log.FromContext(ctx).WithValues("gatewayclass", req.Name) - log.V(3).Info("Reconciling GatewayClass") - - var gc v1beta1.GatewayClass - found := true - - err := r.Get(ctx, req.NamespacedName, &gc) - if err != nil { - if !apierrors.IsNotFound(err) { - log.Error(err, "Failed to get GatewayClass") - return reconcile.Result{}, err - } - found = false - } - - if !found { - r.impl.Remove(req.NamespacedName) - return reconcile.Result{}, nil - } - - r.impl.Upsert(&gc) - return reconcile.Result{}, nil -} diff --git a/pkg/sdk/httproute_controller.go b/pkg/sdk/httproute_controller.go deleted file mode 100644 index d5b6dc2587..0000000000 --- a/pkg/sdk/httproute_controller.go +++ /dev/null @@ -1,62 +0,0 @@ -package sdk - -import ( - "context" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctlr "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -type httpRouteReconciler struct { - client.Client - scheme *runtime.Scheme - impl HTTPRouteImpl -} - -// RegisterHTTPRouteController registers the HTTPRouteController in the manager. -func RegisterHTTPRouteController(mgr manager.Manager, impl HTTPRouteImpl) error { - r := &httpRouteReconciler{ - Client: mgr.GetClient(), - scheme: mgr.GetScheme(), - impl: impl, - } - - return ctlr.NewControllerManagedBy(mgr). - For(&v1beta1.HTTPRoute{}). - Complete(r) -} - -func (r *httpRouteReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - log := log.FromContext(ctx).WithValues("httpRoute", req.NamespacedName) - - log.V(3).Info("Reconciling HTTPRoute") - - found := true - var hr v1beta1.HTTPRoute - err := r.Get(ctx, req.NamespacedName, &hr) - if err != nil { - if !apierrors.IsNotFound(err) { - log.Error(err, "Failed to get HTTPRoute") - return reconcile.Result{}, err - } - found = false - } - - if !found { - log.V(3).Info("Removing HTTPRoute") - - r.impl.Remove(req.NamespacedName) - return reconcile.Result{}, nil - } - - log.V(3).Info("Upserting HTTPRoute") - - r.impl.Upsert(&hr) - return reconcile.Result{}, nil -} diff --git a/pkg/sdk/interfaces.go b/pkg/sdk/interfaces.go deleted file mode 100644 index 7ccc612abe..0000000000 --- a/pkg/sdk/interfaces.go +++ /dev/null @@ -1,39 +0,0 @@ -package sdk - -import ( - apiv1 "k8s.io/api/core/v1" - v1 "k8s.io/api/discovery/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -type GatewayClassImpl interface { - Upsert(gc *v1beta1.GatewayClass) - Remove(nsname types.NamespacedName) -} - -type GatewayImpl interface { - Upsert(*v1beta1.Gateway) - Remove(types.NamespacedName) -} - -type HTTPRouteImpl interface { - Upsert(config *v1beta1.HTTPRoute) - // FIXME(pleshakov): change other interfaces to use types.NamespacedName - Remove(types.NamespacedName) -} - -type ServiceImpl interface { - Upsert(svc *apiv1.Service) - Remove(nsname types.NamespacedName) -} - -type SecretImpl interface { - Upsert(secret *apiv1.Secret) - Remove(name types.NamespacedName) -} - -type EndpointSliceImpl interface { - Upsert(endpSlice *v1.EndpointSlice) - Remove(nsname types.NamespacedName) -} diff --git a/pkg/sdk/secret_controller.go b/pkg/sdk/secret_controller.go deleted file mode 100644 index 9f682d0893..0000000000 --- a/pkg/sdk/secret_controller.go +++ /dev/null @@ -1,62 +0,0 @@ -package sdk - -import ( - "context" - - apiv1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctlr "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -type secretReconciler struct { - client.Client - scheme *runtime.Scheme - impl SecretImpl -} - -// RegisterSecretController registers the SecretController in the manager. -func RegisterSecretController(mgr manager.Manager, impl SecretImpl) error { - r := &secretReconciler{ - Client: mgr.GetClient(), - scheme: mgr.GetScheme(), - impl: impl, - } - - return ctlr.NewControllerManagedBy(mgr). - For(&apiv1.Secret{}). - Complete(r) -} - -func (r *secretReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - log := log.FromContext(ctx).WithValues("secret", req.NamespacedName) - - log.V(3).Info("Reconciling Secret") - - found := true - var secret apiv1.Secret - err := r.Get(ctx, req.NamespacedName, &secret) - if err != nil { - if !apierrors.IsNotFound(err) { - log.Error(err, "Failed to get Secret") - return reconcile.Result{}, err - } - found = false - } - - if !found { - log.V(3).Info("Removing Secret") - - r.impl.Remove(req.NamespacedName) - return reconcile.Result{}, nil - } - - log.V(3).Info("Upserting Secret") - - r.impl.Upsert(&secret) - return reconcile.Result{}, nil -}