refactor: update to the latest version of kubebuilder and add support for hydra v2 (#127)
This commit is contained in:
@ -9,13 +9,13 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
hydrav1alpha1 "github.com/ory/hydra-maester/api/v1alpha1"
|
||||
"github.com/ory/hydra-maester/hydra"
|
||||
@ -166,7 +166,7 @@ func (r *OAuth2ClientReconciler) Reconcile(ctx context.Context, req ctrl.Request
|
||||
var secret apiv1.Secret
|
||||
if err := r.Get(ctx, types.NamespacedName{Name: oauth2client.Spec.SecretName, Namespace: req.Namespace}, &secret); err != nil {
|
||||
if apierrs.IsNotFound(err) {
|
||||
if registerErr := r.registerOAuth2Client(ctx, &oauth2client, nil); registerErr != nil {
|
||||
if registerErr := r.registerOAuth2Client(ctx, &oauth2client); registerErr != nil {
|
||||
return ctrl.Result{}, registerErr
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
@ -200,7 +200,8 @@ func (r *OAuth2ClientReconciler) Reconcile(ctx context.Context, req ctrl.Request
|
||||
fetched, found, err := hydraClient.GetOAuth2Client(string(credentials.ID))
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
|
||||
} else if !found {
|
||||
return ctrl.Result{}, fmt.Errorf("oauth2 client %s not found", credentials.ID)
|
||||
}
|
||||
|
||||
if found {
|
||||
@ -210,7 +211,7 @@ func (r *OAuth2ClientReconciler) Reconcile(ctx context.Context, req ctrl.Request
|
||||
}
|
||||
|
||||
if fetched.Owner != fmt.Sprintf("%s/%s", oauth2client.Name, oauth2client.Namespace) {
|
||||
conflictErr := errors.Errorf("ID provided in secret %s/%s is assigned to another resource", secret.Name, secret.Namespace)
|
||||
conflictErr := fmt.Errorf("ID provided in secret %s/%s is assigned to another resource", secret.Name, secret.Namespace)
|
||||
if updateErr := r.updateReconciliationStatusError(ctx, &oauth2client, hydrav1alpha1.StatusInvalidSecret, conflictErr); updateErr != nil {
|
||||
return ctrl.Result{}, updateErr
|
||||
}
|
||||
@ -223,10 +224,6 @@ func (r *OAuth2ClientReconciler) Reconcile(ctx context.Context, req ctrl.Request
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if registerErr := r.registerOAuth2Client(ctx, &oauth2client, credentials); registerErr != nil {
|
||||
return ctrl.Result{}, registerErr
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
@ -236,7 +233,7 @@ func (r *OAuth2ClientReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func (r *OAuth2ClientReconciler) registerOAuth2Client(ctx context.Context, c *hydrav1alpha1.OAuth2Client, credentials *hydra.Oauth2ClientCredentials) error {
|
||||
func (r *OAuth2ClientReconciler) registerOAuth2Client(ctx context.Context, c *hydrav1alpha1.OAuth2Client) error {
|
||||
if err := r.unregisterOAuth2Clients(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -251,16 +248,8 @@ func (r *OAuth2ClientReconciler) registerOAuth2Client(ctx context.Context, c *hy
|
||||
if updateErr := r.updateReconciliationStatusError(ctx, c, hydrav1alpha1.StatusRegistrationFailed, err); updateErr != nil {
|
||||
return updateErr
|
||||
}
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
if credentials != nil {
|
||||
if _, err := hydraClient.PostOAuth2Client(oauth2client.WithCredentials(credentials)); err != nil {
|
||||
if updateErr := r.updateReconciliationStatusError(ctx, c, hydrav1alpha1.StatusRegistrationFailed, err); updateErr != nil {
|
||||
return updateErr
|
||||
}
|
||||
}
|
||||
return r.ensureEmptyStatusError(ctx, c)
|
||||
return fmt.Errorf("failed to construct hydra client for object: %w", err)
|
||||
}
|
||||
|
||||
created, err := hydraClient.PostOAuth2Client(oauth2client)
|
||||
@ -311,7 +300,8 @@ func (r *OAuth2ClientReconciler) updateRegisteredOAuth2Client(ctx context.Contex
|
||||
if updateErr := r.updateReconciliationStatusError(ctx, c, hydrav1alpha1.StatusUpdateFailed, err); updateErr != nil {
|
||||
return updateErr
|
||||
}
|
||||
return errors.WithStack(err)
|
||||
|
||||
return fmt.Errorf("failed to construct hydra client for object: %w", err)
|
||||
}
|
||||
|
||||
if _, err := hydraClient.PutOAuth2Client(oauth2client.WithCredentials(credentials)); err != nil {
|
||||
@ -353,50 +343,58 @@ func (r *OAuth2ClientReconciler) unregisterOAuth2Clients(ctx context.Context, c
|
||||
|
||||
func (r *OAuth2ClientReconciler) updateReconciliationStatusError(ctx context.Context, c *hydrav1alpha1.OAuth2Client, code hydrav1alpha1.StatusCode, err error) error {
|
||||
r.Log.Error(err, fmt.Sprintf("error processing client %s/%s ", c.Name, c.Namespace), "oauth2client", "register")
|
||||
c.Status.ReconciliationError = hydrav1alpha1.ReconciliationError{
|
||||
Code: code,
|
||||
Description: err.Error(),
|
||||
}
|
||||
c.Status.Conditions = []hydrav1alpha1.OAuth2ClientCondition{
|
||||
{
|
||||
Type: hydrav1alpha1.OAuth2ClientConditionReady,
|
||||
Status: hydrav1alpha1.ConditionFalse,
|
||||
},
|
||||
|
||||
_, err = controllerutil.CreateOrPatch(ctx, r.Client, c, func() error {
|
||||
c.Status.ObservedGeneration = c.Generation
|
||||
c.Status.ReconciliationError = hydrav1alpha1.ReconciliationError{
|
||||
Code: code,
|
||||
Description: err.Error(),
|
||||
}
|
||||
c.Status.Conditions = []hydrav1alpha1.OAuth2ClientCondition{
|
||||
{
|
||||
Type: hydrav1alpha1.OAuth2ClientConditionReady,
|
||||
Status: hydrav1alpha1.ConditionFalse,
|
||||
},
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
r.Log.Error(err, fmt.Sprintf("status update failed for client %s/%s ", c.Name, c.Namespace), "oauth2client", "update status")
|
||||
}
|
||||
|
||||
return r.updateClientStatus(ctx, c)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *OAuth2ClientReconciler) ensureEmptyStatusError(ctx context.Context, c *hydrav1alpha1.OAuth2Client) error {
|
||||
c.Status.ReconciliationError = hydrav1alpha1.ReconciliationError{}
|
||||
c.Status.Conditions = []hydrav1alpha1.OAuth2ClientCondition{
|
||||
{
|
||||
Type: hydrav1alpha1.OAuth2ClientConditionReady,
|
||||
Status: hydrav1alpha1.ConditionTrue,
|
||||
},
|
||||
}
|
||||
return r.updateClientStatus(ctx, c)
|
||||
}
|
||||
_, err := controllerutil.CreateOrPatch(ctx, r.Client, c, func() error {
|
||||
c.Status.ObservedGeneration = c.Generation
|
||||
c.Status.ReconciliationError = hydrav1alpha1.ReconciliationError{}
|
||||
c.Status.Conditions = []hydrav1alpha1.OAuth2ClientCondition{
|
||||
{
|
||||
Type: hydrav1alpha1.OAuth2ClientConditionReady,
|
||||
Status: hydrav1alpha1.ConditionTrue,
|
||||
},
|
||||
}
|
||||
|
||||
func (r *OAuth2ClientReconciler) updateClientStatus(ctx context.Context, c *hydrav1alpha1.OAuth2Client) error {
|
||||
c.Status.ObservedGeneration = c.Generation
|
||||
if err := r.Status().Update(ctx, c); err != nil {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
r.Log.Error(err, fmt.Sprintf("status update failed for client %s/%s ", c.Name, c.Namespace), "oauth2client", "update status")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func parseSecret(secret apiv1.Secret, authMethod hydrav1alpha1.TokenEndpointAuthMethod) (*hydra.Oauth2ClientCredentials, error) {
|
||||
|
||||
id, found := secret.Data[ClientIDKey]
|
||||
if !found {
|
||||
return nil, errors.New(`"client_id property missing"`)
|
||||
return nil, fmt.Errorf("client_id property missing")
|
||||
}
|
||||
|
||||
psw, found := secret.Data[ClientSecretKey]
|
||||
if !found && authMethod != "none" {
|
||||
return nil, errors.New(`"client_secret property missing"`)
|
||||
return nil, fmt.Errorf("client_secret property missing")
|
||||
}
|
||||
|
||||
return &hydra.Oauth2ClientCredentials{
|
||||
@ -423,7 +421,7 @@ func (r *OAuth2ClientReconciler) getHydraClientForClient(
|
||||
|
||||
client, err := r.oauth2ClientFactory(spec, "", false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create oauth2 client from CRD")
|
||||
return nil, fmt.Errorf("cannot create oauth2 client from CRD: %w", err)
|
||||
}
|
||||
|
||||
r.oauth2Clients[key] = client
|
||||
@ -431,9 +429,11 @@ func (r *OAuth2ClientReconciler) getHydraClientForClient(
|
||||
}
|
||||
|
||||
if r.HydraClient == nil {
|
||||
return nil, errors.New("Not default client or other clients configured")
|
||||
return nil, fmt.Errorf("no default client configured")
|
||||
}
|
||||
r.Log.Info(fmt.Sprintf("using default client"))
|
||||
|
||||
r.Log.Info("Using default client")
|
||||
|
||||
return r.HydraClient, nil
|
||||
|
||||
}
|
||||
|
@ -9,16 +9,15 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/stretchr/testify/mock"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/utils/ptr"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
@ -50,7 +49,7 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
tstName, tstClientID, tstSecretName := "test", "testClientID", "my-secret-123"
|
||||
expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}}
|
||||
|
||||
s := scheme.Scheme
|
||||
s := runtime.NewScheme()
|
||||
err := hydrav1alpha1.AddToScheme(s)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -70,7 +69,7 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
mch.On("PostOAuth2Client", AnythingOfType("*hydra.OAuth2ClientJSON")).Return(func(o *hydra.OAuth2ClientJSON) *hydra.OAuth2ClientJSON {
|
||||
return &hydra.OAuth2ClientJSON{
|
||||
ClientID: &tstClientID,
|
||||
Secret: pointer.StringPtr(tstSecret),
|
||||
Secret: ptr.To(tstSecret),
|
||||
GrantTypes: o.GrantTypes,
|
||||
ResponseTypes: o.ResponseTypes,
|
||||
RedirectURIs: o.RedirectURIs,
|
||||
@ -129,7 +128,7 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
tstName, tstSecretName := "test2", "my-secret-456"
|
||||
expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}}
|
||||
|
||||
s := scheme.Scheme
|
||||
s := runtime.NewScheme()
|
||||
err := hydrav1alpha1.AddToScheme(s)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -196,7 +195,7 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
var postedClient *hydra.OAuth2ClientJSON
|
||||
expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}}
|
||||
|
||||
s := scheme.Scheme
|
||||
s := runtime.NewScheme()
|
||||
err := hydrav1alpha1.AddToScheme(s)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -270,9 +269,6 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
Expect(retrieved.Status.ReconciliationError.Code).To(BeEmpty())
|
||||
Expect(retrieved.Status.ReconciliationError.Description).To(BeEmpty())
|
||||
|
||||
Expect(*postedClient.ClientID).To(Equal(tstClientID))
|
||||
Expect(*postedClient.Secret).To(Equal(tstSecret))
|
||||
|
||||
// Ensure that secret doesn't have OwnerReference set
|
||||
ok = client.ObjectKey{Name: tstSecretName, Namespace: tstNamespace}
|
||||
err = k8sClient.Get(context.TODO(), ok, &secret)
|
||||
@ -291,7 +287,7 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
tstName, tstClientID, tstSecretName := "test4", "testClientID-4", "my-secret-000"
|
||||
expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}}
|
||||
|
||||
s := scheme.Scheme
|
||||
s := runtime.NewScheme()
|
||||
err := hydrav1alpha1.AddToScheme(s)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -348,7 +344,7 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(retrieved.Status.ReconciliationError).NotTo(BeNil())
|
||||
Expect(retrieved.Status.ReconciliationError.Code).To(Equal(hydrav1alpha1.StatusInvalidSecret))
|
||||
Expect(retrieved.Status.ReconciliationError.Description).To(Equal(`"client_secret property missing"`))
|
||||
Expect(retrieved.Status.ReconciliationError.Description).To(Equal("client_secret property missing"))
|
||||
|
||||
//delete instance
|
||||
c.Delete(context.TODO(), instance)
|
||||
@ -361,7 +357,7 @@ var _ = Describe("OAuth2Client Controller", func() {
|
||||
tstName, tstClientID, tstSecretName := "test5", "testClientID-5", "my-secret-without-client-secret"
|
||||
expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}}
|
||||
|
||||
s := scheme.Scheme
|
||||
s := runtime.NewScheme()
|
||||
err := hydrav1alpha1.AddToScheme(s)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -457,7 +453,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
}
|
||||
|
||||
// Watch for changes to Api
|
||||
err = c.Watch(&source.Kind{Type: &hydrav1alpha1.OAuth2Client{}}, &handler.EnqueueRequestForObject{})
|
||||
err = c.Watch(source.Kind(mgr.GetCache(), &hydrav1alpha1.OAuth2Client{}), &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
@ -61,8 +62,15 @@ var _ = BeforeSuite(func(done Done) {
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
By("tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Need to retry a bit if the first stop fails due to a bug:
|
||||
// https://github.com/kubernetes-sigs/controller-runtime/issues/1571
|
||||
err := retry.OnError(retry.DefaultBackoff, func(err error) bool {
|
||||
return true
|
||||
}, func() error {
|
||||
return testEnv.Stop()
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
|
Reference in New Issue
Block a user