diff --git a/controller/konnect/ops/me.go b/controller/konnect/ops/me.go new file mode 100644 index 000000000..12f79c72e --- /dev/null +++ b/controller/konnect/ops/me.go @@ -0,0 +1,12 @@ +package ops + +import ( + "context" + + sdkkonnectops "github.com/Kong/sdk-konnect-go/models/operations" +) + +// MeSDK is the interface for Konnect "Me" SDK to get current organization. +type MeSDK interface { + GetOrganizationsMe(ctx context.Context, opts ...sdkkonnectops.Option) (*sdkkonnectops.GetOrganizationsMeResponse, error) +} diff --git a/controller/konnect/ops/ops.go b/controller/konnect/ops/ops.go index 549261697..772309157 100644 --- a/controller/konnect/ops/ops.go +++ b/controller/konnect/ops/ops.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - sdkkonnectgo "github.com/Kong/sdk-konnect-go" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -46,7 +45,7 @@ func Create[ TEnt constraints.EntityType[T], ]( ctx context.Context, - sdk *sdkkonnectgo.SDK, + sdk SDKWrapper, cl client.Client, e *T, ) (*T, error) { @@ -54,17 +53,17 @@ func Create[ switch ent := any(e).(type) { case *konnectv1alpha1.KonnectGatewayControlPlane: - return e, createControlPlane(ctx, sdk.ControlPlanes, ent) + return e, createControlPlane(ctx, sdk.GetControlPlaneSDK(), ent) case *configurationv1alpha1.KongService: - return e, createService(ctx, sdk.Services, ent) + return e, createService(ctx, sdk.GetServicesSDK(), ent) case *configurationv1alpha1.KongRoute: - return e, createRoute(ctx, sdk.Routes, ent) + return e, createRoute(ctx, sdk.GetRoutesSDK(), ent) case *configurationv1.KongConsumer: - return e, createConsumer(ctx, sdk.Consumers, ent) + return e, createConsumer(ctx, sdk.GetConsumersSDK(), ent) case *configurationv1beta1.KongConsumerGroup: - return e, createConsumerGroup(ctx, sdk.ConsumerGroups, ent) + return e, createConsumerGroup(ctx, sdk.GetConsumerGroupsSDK(), ent) case *configurationv1alpha1.KongPluginBinding: - return e, createPlugin(ctx, cl, sdk.Plugins, ent) + return e, createPlugin(ctx, cl, sdk.GetPluginSDK(), ent) // --------------------------------------------------------------------- // TODO: add other Konnect types @@ -79,7 +78,7 @@ func Create[ func Delete[ T constraints.SupportedKonnectEntityType, TEnt constraints.EntityType[T], -](ctx context.Context, sdk *sdkkonnectgo.SDK, cl client.Client, e *T) error { +](ctx context.Context, sdk SDKWrapper, cl client.Client, e *T) error { ent := TEnt(e) if ent.GetKonnectStatus().GetKonnectID() == "" { return fmt.Errorf( @@ -92,17 +91,17 @@ func Delete[ switch ent := any(e).(type) { case *konnectv1alpha1.KonnectGatewayControlPlane: - return deleteControlPlane(ctx, sdk.ControlPlanes, ent) + return deleteControlPlane(ctx, sdk.GetControlPlaneSDK(), ent) case *configurationv1alpha1.KongService: - return deleteService(ctx, sdk.Services, ent) + return deleteService(ctx, sdk.GetServicesSDK(), ent) case *configurationv1alpha1.KongRoute: - return deleteRoute(ctx, sdk.Routes, ent) + return deleteRoute(ctx, sdk.GetRoutesSDK(), ent) case *configurationv1.KongConsumer: - return deleteConsumer(ctx, sdk.Consumers, ent) + return deleteConsumer(ctx, sdk.GetConsumersSDK(), ent) case *configurationv1beta1.KongConsumerGroup: - return deleteConsumerGroup(ctx, sdk.ConsumerGroups, ent) + return deleteConsumerGroup(ctx, sdk.GetConsumerGroupsSDK(), ent) case *configurationv1alpha1.KongPluginBinding: - return deletePlugin(ctx, sdk.Plugins, ent) + return deletePlugin(ctx, sdk.GetPluginSDK(), ent) // --------------------------------------------------------------------- // TODO: add other Konnect types @@ -117,7 +116,7 @@ func Delete[ func Update[ T constraints.SupportedKonnectEntityType, TEnt constraints.EntityType[T], -](ctx context.Context, sdk *sdkkonnectgo.SDK, syncPeriod time.Duration, cl client.Client, e *T) (ctrl.Result, error) { +](ctx context.Context, sdk SDKWrapper, syncPeriod time.Duration, cl client.Client, e *T) (ctrl.Result, error) { var ( ent = TEnt(e) condProgrammed, ok = k8sutils.GetCondition(conditions.KonnectEntityProgrammedConditionType, ent) @@ -155,17 +154,17 @@ func Update[ switch ent := any(e).(type) { case *konnectv1alpha1.KonnectGatewayControlPlane: - return ctrl.Result{}, updateControlPlane(ctx, sdk.ControlPlanes, ent) + return ctrl.Result{}, updateControlPlane(ctx, sdk.GetControlPlaneSDK(), ent) case *configurationv1alpha1.KongService: - return ctrl.Result{}, updateService(ctx, sdk.Services, ent) + return ctrl.Result{}, updateService(ctx, sdk.GetServicesSDK(), ent) case *configurationv1alpha1.KongRoute: - return ctrl.Result{}, updateRoute(ctx, sdk.Routes, cl, ent) + return ctrl.Result{}, updateRoute(ctx, sdk.GetRoutesSDK(), cl, ent) case *configurationv1.KongConsumer: - return ctrl.Result{}, updateConsumer(ctx, sdk.Consumers, cl, ent) + return ctrl.Result{}, updateConsumer(ctx, sdk.GetConsumersSDK(), cl, ent) case *configurationv1beta1.KongConsumerGroup: - return ctrl.Result{}, updateConsumerGroup(ctx, sdk.ConsumerGroups, cl, ent) + return ctrl.Result{}, updateConsumerGroup(ctx, sdk.GetConsumerGroupsSDK(), cl, ent) case *configurationv1alpha1.KongPluginBinding: - return ctrl.Result{}, updatePlugin(ctx, sdk.Plugins, cl, ent) + return ctrl.Result{}, updatePlugin(ctx, sdk.GetPluginSDK(), cl, ent) // --------------------------------------------------------------------- // TODO: add other Konnect types diff --git a/controller/konnect/ops/plugin.go b/controller/konnect/ops/plugin.go index c6834948e..4eac06f93 100644 --- a/controller/konnect/ops/plugin.go +++ b/controller/konnect/ops/plugin.go @@ -7,6 +7,7 @@ import ( sdkkonnectops "github.com/Kong/sdk-konnect-go/models/operations" ) +// PluginSDK is the interface for Konnect plugin SDK. type PluginSDK interface { CreatePlugin(ctx context.Context, controlPlaneID string, plugin sdkkonnectcomp.PluginInput, opts ...sdkkonnectops.Option) (*sdkkonnectops.CreatePluginResponse, error) UpsertPlugin(ctx context.Context, request sdkkonnectops.UpsertPluginRequest, opts ...sdkkonnectops.Option) (*sdkkonnectops.UpsertPluginResponse, error) diff --git a/controller/konnect/ops/sdkfactory.go b/controller/konnect/ops/sdkfactory.go new file mode 100644 index 000000000..35923aa26 --- /dev/null +++ b/controller/konnect/ops/sdkfactory.go @@ -0,0 +1,87 @@ +package ops + +import ( + sdkkonnectgo "github.com/Kong/sdk-konnect-go" + sdkkonnectcomp "github.com/Kong/sdk-konnect-go/models/components" +) + +// SDKWrapper is a wrapper of Konnect SDK to allow using mock SDKs in tests. +type SDKWrapper interface { + GetControlPlaneSDK() ControlPlaneSDK + GetServicesSDK() ServicesSDK + GetRoutesSDK() RoutesSDK + GetConsumersSDK() ConsumersSDK + GetConsumerGroupsSDK() ConsumerGroupSDK + GetPluginSDK() PluginSDK + GetMeSDK() MeSDK +} + +type sdkWrapper struct { + sdk *sdkkonnectgo.SDK +} + +var _ SDKWrapper = sdkWrapper{} + +// GetControlPlaneSDK returns the SDK to operate Konenct control planes. +func (w sdkWrapper) GetControlPlaneSDK() ControlPlaneSDK { + return w.sdk.ControlPlanes +} + +// GetServicesSDK returns the SDK to operate Kong services. +func (w sdkWrapper) GetServicesSDK() ServicesSDK { + return w.sdk.Services +} + +// GetRoutesSDK returns the SDK to operate Kong routes. +func (w sdkWrapper) GetRoutesSDK() RoutesSDK { + return w.sdk.Routes +} + +// GetConsumersSDK returns the SDK to operate Kong consumers. +func (w sdkWrapper) GetConsumersSDK() ConsumersSDK { + return w.sdk.Consumers +} + +// GetConsumerGroupsSDK returns the SDK to operate Kong consumer groups. +func (w sdkWrapper) GetConsumerGroupsSDK() ConsumerGroupSDK { + return w.sdk.ConsumerGroups +} + +// GetPluginSDK returns the SDK to operate plugins. +func (w sdkWrapper) GetPluginSDK() PluginSDK { + return w.sdk.Plugins +} + +// GetMeSDK returns the "me" SDK to get current organization. +func (w sdkWrapper) GetMeSDK() MeSDK { + return w.sdk.Me +} + +// SDKToken is a token used to authenticate with the Konnect SDK. +type SDKToken string + +// SDKFactory is a factory for creating Konnect SDKs. +type SDKFactory interface { + NewKonnectSDK(serverURL string, token SDKToken) SDKWrapper +} + +type sdkFactory struct{} + +// NewSDKFactory creates a new SDKFactory. +func NewSDKFactory() SDKFactory { + return sdkFactory{} +} + +// NewKonnectSDK creates a new Konnect SDK. +func (f sdkFactory) NewKonnectSDK(serverURL string, token SDKToken) SDKWrapper { + return sdkWrapper{ + sdk: sdkkonnectgo.New( + sdkkonnectgo.WithSecurity( + sdkkonnectcomp.Security{ + PersonalAccessToken: sdkkonnectgo.String(string(token)), + }, + ), + sdkkonnectgo.WithServerURL(serverURL), + ), + } +} diff --git a/controller/konnect/reconciler_generic.go b/controller/konnect/reconciler_generic.go index fcd16b455..5f94a0a4a 100644 --- a/controller/konnect/reconciler_generic.go +++ b/controller/konnect/reconciler_generic.go @@ -39,7 +39,7 @@ const ( // KonnectEntityReconciler reconciles a Konnect entities. // It uses the generic type constraints to constrain the supported types. type KonnectEntityReconciler[T constraints.SupportedKonnectEntityType, TEnt constraints.EntityType[T]] struct { - sdkFactory SDKFactory + sdkFactory ops.SDKFactory DevelopmentMode bool Client client.Client SyncPeriod time.Duration @@ -66,7 +66,7 @@ func NewKonnectEntityReconciler[ T constraints.SupportedKonnectEntityType, TEnt constraints.EntityType[T], ]( - sdkFactory SDKFactory, + sdkFactory ops.SDKFactory, developmentMode bool, client client.Client, opts ...KonnectEntityReconcilerOption[T, TEnt], @@ -288,7 +288,7 @@ func (r *KonnectEntityReconciler[T, TEnt]) Reconcile( // because the token is retrieved in runtime through KonnectAPIAuthConfiguration. sdk := r.sdkFactory.NewKonnectSDK( "https://"+apiAuth.Spec.ServerURL, - SDKToken(token), + ops.SDKToken(token), ) if delTimestamp := ent.GetDeletionTimestamp(); !delTimestamp.IsZero() { diff --git a/controller/konnect/reconciler_generic_test.go b/controller/konnect/reconciler_generic_test.go index 92ac0af91..3619c6646 100644 --- a/controller/konnect/reconciler_generic_test.go +++ b/controller/konnect/reconciler_generic_test.go @@ -9,6 +9,7 @@ import ( fakectrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/gateway-operator/controller/konnect/constraints" + "github.com/kong/gateway-operator/controller/konnect/ops" "github.com/kong/gateway-operator/modules/manager/scheme" configurationv1 "github.com/kong/kubernetes-configuration/api/configuration/v1" @@ -38,7 +39,7 @@ func testNewKonnectEntityReconciler[ ) { t.Helper() - sdkFactory := NewSDKFactory() + sdkFactory := ops.NewSDKFactory() t.Run(ent.GetTypeName(), func(t *testing.T) { cl := fakectrlruntimeclient.NewFakeClient() diff --git a/controller/konnect/reconciler_konnectapiauth.go b/controller/konnect/reconciler_konnectapiauth.go index 8e8823044..c82898528 100644 --- a/controller/konnect/reconciler_konnectapiauth.go +++ b/controller/konnect/reconciler_konnectapiauth.go @@ -19,6 +19,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "github.com/kong/gateway-operator/controller/konnect/conditions" + "github.com/kong/gateway-operator/controller/konnect/ops" "github.com/kong/gateway-operator/controller/pkg/log" k8sutils "github.com/kong/gateway-operator/pkg/utils/kubernetes" @@ -27,7 +28,7 @@ import ( // KonnectAPIAuthConfigurationReconciler reconciles a KonnectAPIAuthConfiguration object. type KonnectAPIAuthConfigurationReconciler struct { - SDKFactory SDKFactory + SDKFactory ops.SDKFactory DevelopmentMode bool Client client.Client } @@ -45,7 +46,7 @@ const ( // NewKonnectAPIAuthConfigurationReconciler creates a new KonnectAPIAuthConfigurationReconciler. func NewKonnectAPIAuthConfigurationReconciler( - sdkFactory SDKFactory, + sdkFactory ops.SDKFactory, developmentMode bool, client client.Client, ) *KonnectAPIAuthConfigurationReconciler { @@ -138,7 +139,7 @@ func (r *KonnectAPIAuthConfigurationReconciler) Reconcile( } sdk := r.SDKFactory.NewKonnectSDK( serverURL, - SDKToken(token), + ops.SDKToken(token), ) // TODO(pmalek): check if api auth config has a valid status condition @@ -150,7 +151,7 @@ func (r *KonnectAPIAuthConfigurationReconciler) Reconcile( // NOTE: This is needed because currently the SDK only lists the prod global API as supported: // https://github.com/Kong/sdk-konnect-go/blob/999d9a987e1aa7d2e09ac11b1450f4563adf21ea/models/operations/getorganizationsme.go#L10-L12 - respOrg, err := sdk.Me.GetOrganizationsMe(ctx, sdkkonnectops.WithServerURL("https://"+apiAuth.Spec.ServerURL)) + respOrg, err := sdk.GetMeSDK().GetOrganizationsMe(ctx, sdkkonnectops.WithServerURL("https://"+apiAuth.Spec.ServerURL)) if err != nil { logger.Error(err, "failed to get organization info from Konnect") if cond, ok := k8sutils.GetCondition(conditions.KonnectEntityAPIAuthConfigurationValidConditionType, &apiAuth); !ok || diff --git a/controller/konnect/sdkfactory.go b/controller/konnect/sdkfactory.go deleted file mode 100644 index 07b6fb7cd..000000000 --- a/controller/konnect/sdkfactory.go +++ /dev/null @@ -1,33 +0,0 @@ -package konnect - -import ( - sdkkonnectgo "github.com/Kong/sdk-konnect-go" - sdkkonnectcomp "github.com/Kong/sdk-konnect-go/models/components" -) - -// SDKToken is a token used to authenticate with the Konnect SDK. -type SDKToken string - -// SDKFactory is a factory for creating Konnect SDKs. -type SDKFactory interface { - NewKonnectSDK(serverURL string, token SDKToken) *sdkkonnectgo.SDK -} - -type sdkFactory struct{} - -// NewSDKFactory creates a new SDKFactory. -func NewSDKFactory() SDKFactory { - return sdkFactory{} -} - -// NewKonnectSDK creates a new Konnect SDK. -func (f sdkFactory) NewKonnectSDK(serverURL string, token SDKToken) *sdkkonnectgo.SDK { - return sdkkonnectgo.New( - sdkkonnectgo.WithSecurity( - sdkkonnectcomp.Security{ - PersonalAccessToken: sdkkonnectgo.String(string(token)), - }, - ), - sdkkonnectgo.WithServerURL(serverURL), - ) -} diff --git a/modules/manager/controller_setup.go b/modules/manager/controller_setup.go index fb869f7e3..6eb46c04a 100644 --- a/modules/manager/controller_setup.go +++ b/modules/manager/controller_setup.go @@ -22,6 +22,7 @@ import ( "github.com/kong/gateway-operator/controller/gatewayclass" "github.com/kong/gateway-operator/controller/kongplugininstallation" "github.com/kong/gateway-operator/controller/konnect" + konnectops "github.com/kong/gateway-operator/controller/konnect/ops" "github.com/kong/gateway-operator/controller/specialized" "github.com/kong/gateway-operator/internal/utils/index" dataplanevalidator "github.com/kong/gateway-operator/internal/validation/dataplane" @@ -305,7 +306,7 @@ func SetupControllers(mgr manager.Manager, c *Config) (map[string]ControllerDef, // Konnect controllers if c.KonnectControllersEnabled { - sdkFactory := konnect.NewSDKFactory() + sdkFactory := konnectops.NewSDKFactory() controllers[KonnectAPIAuthConfigurationControllerName] = ControllerDef{ Enabled: c.KonnectControllersEnabled,