Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(konnect): add KonnectAPIAuthConfiguration reconciler #456

Merged
merged 3 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions config/rbac/role/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,24 @@ rules:
- get
- patch
- update
- apiGroups:
- konnect.konghq.com
resources:
- konnectapiauthconfigurations
verbs:
- get
- list
- patch
- update
pmalek marked this conversation as resolved.
Show resolved Hide resolved
- watch
- apiGroups:
- konnect.konghq.com
resources:
- konnectapiauthconfigurations/status
verbs:
- get
- patch
- update
- apiGroups:
- networking.k8s.io
resources:
Expand Down
4 changes: 1 addition & 3 deletions controller/konnect/constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

configurationv1 "github.com/kong/kubernetes-configuration/api/configuration/v1"
configurationv1alpha1 "github.com/kong/kubernetes-configuration/api/configuration/v1alpha1"
configurationv1beta1 "github.com/kong/kubernetes-configuration/api/configuration/v1beta1"
konnectv1alpha1 "github.com/kong/kubernetes-configuration/api/konnect/v1alpha1"
)

Expand All @@ -15,8 +14,7 @@ import (
type SupportedKonnectEntityType interface {
configurationv1alpha1.KongService |
configurationv1alpha1.KongRoute |
configurationv1.KongConsumer |
configurationv1beta1.KongConsumerGroup
configurationv1.KongConsumer
// TODO: add other types

GetTypeName() string
Expand Down
17 changes: 10 additions & 7 deletions controller/konnect/reconciler_generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (r *KonnectEntityReconciler[T, TEnt]) Reconcile(
}

// Update the status if the reference is resolved and it's not as expected.
if cond, present := k8sutils.GetCondition(KonnectEntityAPIAuthConfigurationResolvedRefConditionType, &apiAuth.Status); !present ||
if cond, present := k8sutils.GetCondition(KonnectEntityAPIAuthConfigurationResolvedRefConditionType, &apiAuth); !present ||
cond.Status != metav1.ConditionTrue ||
cond.ObservedGeneration != apiAuth.GetGeneration() ||
cond.Reason != KonnectEntityAPIAuthConfigurationResolvedRefReasonResolvedRef {
Expand All @@ -152,21 +152,21 @@ func (r *KonnectEntityReconciler[T, TEnt]) Reconcile(
KonnectEntityAPIAuthConfigurationResolvedRefReasonResolvedRef,
fmt.Sprintf("KonnectAPIAuthConfiguration reference %s is resolved", apiAuthRef),
); err != nil || res.Requeue {
return ctrl.Result{}, err
return res, err
}
return ctrl.Result{}, nil
}

// Check if the referenced APIAuthConfiguration is valid.
if cond, present := k8sutils.GetCondition(KonnectEntityAPIAuthConfigurationValidConditionType, &apiAuth.Status); !present || cond.Status != metav1.ConditionTrue {
if cond, present := k8sutils.GetCondition(KonnectEntityAPIAuthConfigurationValidConditionType, &apiAuth); !present || cond.Status != metav1.ConditionTrue {
if res, err := updateStatusWithCondition(
ctx, r.Client, ent,
KonnectEntityAPIAuthConfigurationValidConditionType,
metav1.ConditionFalse,
KonnectEntityAPIAuthConfigurationReasonInvalid,
fmt.Sprintf("referenced KonnectAPIAuthConfiguration %s is invalid", apiAuthRef),
); err != nil || res.Requeue {
return ctrl.Result{}, err
return res, err
}

return ctrl.Result{}, nil
Expand All @@ -182,7 +182,7 @@ func (r *KonnectEntityReconciler[T, TEnt]) Reconcile(
KonnectEntityAPIAuthConfigurationReasonValid,
fmt.Sprintf("referenced KonnectAPIAuthConfiguration %s is valid", apiAuthRef),
); err != nil || res.Requeue {
return ctrl.Result{}, err
return res, err
}
return ctrl.Result{}, nil
}
Expand Down Expand Up @@ -297,10 +297,13 @@ func (r *KonnectEntityReconciler[T, TEnt]) Reconcile(
}, nil
}

func updateStatusWithCondition[T SupportedKonnectEntityType, TEnt EntityType[T]](
func updateStatusWithCondition[T interface {
client.Object
k8sutils.ConditionsAware
}](
ctx context.Context,
client client.Client,
ent TEnt,
ent T,
conditionType consts.ConditionType,
conditionStatus metav1.ConditionStatus,
conditionReason consts.ConditionReason,
Expand Down
151 changes: 151 additions & 0 deletions controller/konnect/reconciler_konnectapiauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package konnect

import (
"context"
"fmt"
"time"

sdkkonnectgoops "github.com/Kong/sdk-konnect-go/models/operations"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kong/gateway-operator/controller/pkg/log"
k8sutils "github.com/kong/gateway-operator/pkg/utils/kubernetes"

konnectv1alpha1 "github.com/kong/kubernetes-configuration/api/konnect/v1alpha1"
)

// KonnectAPIAuthConfigurationReconciler reconciles a KonnectAPIAuthConfiguration object.
type KonnectAPIAuthConfigurationReconciler struct {
pmalek marked this conversation as resolved.
Show resolved Hide resolved
SDKFactory SDKFactory
DevelopmentMode bool
Client client.Client
}

// NewKonnectAPIAuthConfigurationReconciler creates a new KonnectAPIAuthConfigurationReconciler.
func NewKonnectAPIAuthConfigurationReconciler(
sdkFactory SDKFactory,
developmentMode bool,
client client.Client,
) *KonnectAPIAuthConfigurationReconciler {
return &KonnectAPIAuthConfigurationReconciler{
SDKFactory: sdkFactory,
DevelopmentMode: developmentMode,
Client: client,
}
}

// SetupWithManager sets up the controller with the Manager.
func (r *KonnectAPIAuthConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error {
b := ctrl.NewControllerManagedBy(mgr).
For(&konnectv1alpha1.KonnectAPIAuthConfiguration{}).
Named("KonnectAPIAuthConfiguration")

return b.Complete(r)
}

// Reconcile reconciles a KonnectAPIAuthConfiguration object.
func (r *KonnectAPIAuthConfigurationReconciler) Reconcile(
ctx context.Context, req ctrl.Request,
) (ctrl.Result, error) {
var apiAuth konnectv1alpha1.KonnectAPIAuthConfiguration
if err := r.Client.Get(ctx, req.NamespacedName, &apiAuth); err != nil {
if k8serrors.IsNotFound(err) {
return ctrl.Result{}, nil
}
return ctrl.Result{}, err
}

var (
entityTypeName = "KonnectAPIAuthConfiguration"
logger = log.GetLogger(ctx, entityTypeName, r.DevelopmentMode)
)

log.Debug(logger, "reconciling", apiAuth)
if !apiAuth.GetDeletionTimestamp().IsZero() {
logger.Info("resource is being deleted")
// wait for termination grace period before cleaning up
if apiAuth.GetDeletionTimestamp().After(time.Now()) {
logger.Info("resource still under grace period, requeueing")
return ctrl.Result{
// Requeue when grace period expires.
// If deletion timestamp is changed,
// the update will trigger another round of reconciliation.
// so we do not consider updates of deletion timestamp here.
RequeueAfter: time.Until(apiAuth.GetDeletionTimestamp().Time),
}, nil
}

return ctrl.Result{}, nil
}

sdk := r.SDKFactory.NewKonnectSDK(
"https://"+apiAuth.Spec.ServerURL,
SDKToken(apiAuth.Spec.Token),
)

// TODO(pmalek): check if api auth config has a valid status condition
// If not then return an error.

// NOTE: /organizations/me is not public in OpenAPI spec so we can use it
// but not using the SDK
// https://kongstrong.slack.com/archives/C04RXLGNB6K/p1719830395775599?thread_ts=1719406468.883729&cid=C04RXLGNB6K

// 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, sdkkonnectgoops.WithServerURL("https://"+apiAuth.Spec.ServerURL))
if err != nil {
if cond, ok := k8sutils.GetCondition(KonnectEntityAPIAuthConfigurationValidConditionType, &apiAuth); !ok ||
cond.Status != metav1.ConditionFalse ||
cond.Reason != KonnectEntityAPIAuthConfigurationReasonInvalid ||
cond.ObservedGeneration != apiAuth.GetGeneration() ||
apiAuth.Status.OrganizationID != "" ||
apiAuth.Status.ServerURL != apiAuth.Spec.ServerURL {

apiAuth.Status.OrganizationID = ""
apiAuth.Status.ServerURL = apiAuth.Spec.ServerURL

res, err := updateStatusWithCondition(
ctx, r.Client, &apiAuth,
KonnectEntityAPIAuthConfigurationValidConditionType,
metav1.ConditionFalse,
KonnectEntityAPIAuthConfigurationReasonInvalid,
err.Error(),
)
if err != nil || res.Requeue {
return res, err
}
return ctrl.Result{}, fmt.Errorf("failed to get organization info from Konnect: %w", err)
}
return ctrl.Result{}, fmt.Errorf("failed to get organization info from Konnect: %w", err)
}

// Update the status only if it would change to prevent unnecessary updates.
if cond, ok := k8sutils.GetCondition(KonnectEntityAPIAuthConfigurationValidConditionType, &apiAuth); !ok ||
cond.Status != metav1.ConditionTrue ||
cond.Message != "" ||
cond.Reason != KonnectEntityAPIAuthConfigurationReasonValid ||
cond.ObservedGeneration != apiAuth.GetGeneration() ||
apiAuth.Status.OrganizationID != *respOrg.MeOrganization.ID ||
apiAuth.Status.ServerURL != apiAuth.Spec.ServerURL {

apiAuth.Status.OrganizationID = *respOrg.MeOrganization.ID
apiAuth.Status.ServerURL = apiAuth.Spec.ServerURL

res, err := updateStatusWithCondition(
ctx, r.Client, &apiAuth,
KonnectEntityAPIAuthConfigurationValidConditionType,
metav1.ConditionTrue,
KonnectEntityAPIAuthConfigurationReasonValid,
fmt.Sprintf("Referenced KonnectAPIAuthConfiguration %s is valid", client.ObjectKeyFromObject(&apiAuth)),
)
if err != nil || res.Requeue {
return res, err
}
return ctrl.Result{}, nil
}

return ctrl.Result{}, nil
}
4 changes: 4 additions & 0 deletions controller/konnect/reconciler_konnectapiauth_rbac.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package konnect

//+kubebuilder:rbac:groups=konnect.konghq.com,resources=konnectapiauthconfigurations,verbs=get;list;watch;update;patch
//+kubebuilder:rbac:groups=konnect.konghq.com,resources=konnectapiauthconfigurations/status,verbs=get;update;patch
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/cloudflare/cfssl v1.6.5
github.com/go-logr/logr v1.4.2
github.com/google/uuid v1.6.0
github.com/kong/kubernetes-configuration v0.0.0-20240801155137-c98bf64df469
github.com/kong/kubernetes-configuration v0.0.0-20240801170722-d6586edd1b81
github.com/kong/kubernetes-ingress-controller/v3 v3.2.3
github.com/kong/kubernetes-telemetry v0.1.4
github.com/kong/kubernetes-testing-framework v0.47.1
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg6
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/Kong/sdk-konnect-go v0.0.0-20240723160412-999d9a987e1a h1:0mQhPVVA2/+uTVmoKrEIGf+0eTrNyr80Ssv1zGs/1Lk=
github.com/Kong/sdk-konnect-go v0.0.0-20240723160412-999d9a987e1a/go.mod h1:ipu67aQNnwDzu/LXKePG46cVqkkZnAHKWpsbhTEI8xE=
github.com/Kong/sdk-konnect-go v0.0.0-20240801091928-39a27951b473 h1:vIYHnHxEcWTGPZ113NPlLvWEOWYaPRYwwpuoU2J64yY=
github.com/Kong/sdk-konnect-go v0.0.0-20240801091928-39a27951b473/go.mod h1:75YzLhfnYfmCvBJgkafzVuREwBAec2/jihCW2fyn6hY=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
Expand Down Expand Up @@ -217,10 +219,16 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kong/go-kong v0.57.0 h1:e+4bHTzcO0xhFPVyGIUtlO+B4E4l14k55NH8Vjw6ORY=
github.com/kong/go-kong v0.57.0/go.mod h1:gyNwyP1fzztT6sX/0/ygMQ30OiRMIQ51b2jSfstMrcU=
github.com/kong/kubernetes-configuration v0.0.0-20240726122834-c10e8297f9e6 h1:mi0P9KZSYbI1bffC+dwz0lesjHgd3AS4W/762C6qJHs=
github.com/kong/kubernetes-configuration v0.0.0-20240726122834-c10e8297f9e6/go.mod h1:kZTKzwQ68Wk2n8W8Em0RsYTL2yVNbCWU+5b9w1WU+Hs=
github.com/kong/kubernetes-configuration v0.0.0-20240731182605-13d36c4c628c h1:D+JNLhsjs3I9R4tUp9/0EknDG2DayVny20rEGj33o/w=
github.com/kong/kubernetes-configuration v0.0.0-20240731182605-13d36c4c628c/go.mod h1:kZTKzwQ68Wk2n8W8Em0RsYTL2yVNbCWU+5b9w1WU+Hs=
github.com/kong/kubernetes-configuration v0.0.0-20240801095618-0ed30e4054cb h1:GUMgT3qqNjLV1Wdl8D6fskEaN/vof/FRhRbicIkUKpg=
github.com/kong/kubernetes-configuration v0.0.0-20240801095618-0ed30e4054cb/go.mod h1:kZTKzwQ68Wk2n8W8Em0RsYTL2yVNbCWU+5b9w1WU+Hs=
github.com/kong/kubernetes-configuration v0.0.0-20240801155137-c98bf64df469 h1:wzRoAf4byqST4BvmqPne/GL56VrnsrRM3A8ePuvOyf4=
github.com/kong/kubernetes-configuration v0.0.0-20240801155137-c98bf64df469/go.mod h1:kZTKzwQ68Wk2n8W8Em0RsYTL2yVNbCWU+5b9w1WU+Hs=
github.com/kong/kubernetes-configuration v0.0.0-20240801170722-d6586edd1b81 h1:yEbqo7RdTQ7iGEA1PIpQGfO7D5EN7jj2qdPOGN9ipow=
github.com/kong/kubernetes-configuration v0.0.0-20240801170722-d6586edd1b81/go.mod h1:kZTKzwQ68Wk2n8W8Em0RsYTL2yVNbCWU+5b9w1WU+Hs=
github.com/kong/kubernetes-ingress-controller/v3 v3.2.3 h1:SQ/0hfceGmsvzbkCUxiJUv1ELcFRp4d6IzvYGfHct9o=
github.com/kong/kubernetes-ingress-controller/v3 v3.2.3/go.mod h1:gshVZnDU2FTe/95I3vSJPsH2kyB8zR+GpUIieCyt8C4=
github.com/kong/kubernetes-telemetry v0.1.4 h1:Yz7OlECxWKgNRG1wJ5imA4+H0dQEpdU9d86uhwUVpu4=
Expand Down
3 changes: 3 additions & 0 deletions modules/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func New(m metadata.Info) *CLI {
// controllers for specialized APIs and features
flagSet.BoolVar(&cfg.AIGatewayControllerEnabled, "enable-controller-aigateway", false, "Enable the AIGateway controller. (Experimental).")

// controllers for Konnect APIs
flagSet.BoolVar(&cfg.KonnectControllersEnabled, "enable-controller-konnect", false, "Enable the Konnect controllers.")

// webhook and validation options
flagSet.BoolVar(&deferCfg.ValidatingWebhookEnabled, "enable-validating-webhook", true, "Enable the validating webhook.")

Expand Down
1 change: 1 addition & 0 deletions modules/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func expectedDefaultCfg() manager.Config {
ControlPlaneControllerEnabled: true,
DataPlaneControllerEnabled: true,
DataPlaneBlueGreenControllerEnabled: true,
KonnectControllersEnabled: false,
ValidatingWebhookEnabled: true,
LoggerOpts: &zap.Options{},
}
Expand Down
16 changes: 16 additions & 0 deletions modules/manager/controller_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/kong/gateway-operator/controller/dataplane"
"github.com/kong/gateway-operator/controller/gateway"
"github.com/kong/gateway-operator/controller/gatewayclass"
"github.com/kong/gateway-operator/controller/konnect"
"github.com/kong/gateway-operator/controller/specialized"
"github.com/kong/gateway-operator/internal/utils/index"
dataplanevalidator "github.com/kong/gateway-operator/internal/validation/dataplane"
Expand All @@ -46,6 +47,8 @@ const (
DataPlaneOwnedDeploymentFinalizerControllerName = "DataPlaneOwnedDeploymentFinalizer"
// AIGatewayControllerName is the name of the GatewayClass controller.
AIGatewayControllerName = "AIGateway"
// KonnectAPIAuthConfigurationControllerName is the name of the KonnectAPIAuthConfiguration controller.
KonnectAPIAuthConfigurationControllerName = "KonnectAPIAuthConfiguration"
)

// SetupControllersShim runs SetupControllers and returns its result as a slice of the map values.
Expand Down Expand Up @@ -271,5 +274,18 @@ func SetupControllers(mgr manager.Manager, c *Config) (map[string]ControllerDef,
},
}

// Konnect controllers
if c.KonnectControllersEnabled {
sdkFactory := konnect.NewSDKFactory()
controllers[KonnectAPIAuthConfigurationControllerName] = ControllerDef{
Enabled: c.KonnectControllersEnabled,
Controller: konnect.NewKonnectAPIAuthConfigurationReconciler(
sdkFactory,
c.DevelopmentMode,
mgr.GetClient(),
),
}
}

return controllers, nil
}
3 changes: 3 additions & 0 deletions modules/manager/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ type Config struct {
// Controllers for specialty APIs and experimental features.
AIGatewayControllerEnabled bool

// Controllers for Konnect APIs.
KonnectControllersEnabled bool

// webhook and validation options
ValidatingWebhookEnabled bool
}
Expand Down
Loading