Make runnable binary

This commit is contained in:
paul 2021-01-10 23:49:22 +01:00
parent 7eedd41bb9
commit b3c1d98534
11 changed files with 368 additions and 23 deletions

22
controllers/helpers.go Normal file
View file

@ -0,0 +1,22 @@
package controllers
// Helper functions to check and remove string from a slice of strings.
func containsString(slice []string, s string) bool {
for _, item := range slice {
if item == s {
return true
}
}
return false
}
// Helper functions to check and remove string from a slice of strings.
func removeString(slice []string, s string) (result []string) {
for _, item := range slice {
if item == s {
continue
}
result = append(result, item)
}
return
}

View file

@ -0,0 +1,98 @@
package keycloak
import (
"context"
"log"
"sync"
"time"
"github.com/Nerzal/gocloak/v7"
)
// Keycloak contains all information to administrate keycloak
// and stay logged in
type Keycloak struct {
mutex sync.Mutex
client gocloak.GoCloak
accessToken string
validUntil time.Time
user, pass, realm string
}
func (kc *Keycloak) CreateRealmIfNotExists(ctx context.Context, realm gocloak.RealmRepresentation) error {
_, err := kc.client.CreateRealm(ctx, kc.getToken(), realm)
if isConflict(err) {
log.Printf("Realm '%s' already exists, not updated", *realm.Realm)
return nil
}
return err
}
func (kc *Keycloak) CreateProviderIfNotExists(ctx context.Context, realm string, provider gocloak.IdentityProviderRepresentation) error {
_, err := kc.client.CreateIdentityProvider(ctx, kc.getToken(), realm, provider)
if isConflict(err) {
log.Printf("Provider '%s/%s' already exists, not updated", realm, *provider.Alias)
return nil
}
return err
}
func (kc *Keycloak) CreateClientIfNotExists(ctx context.Context, realm string, c gocloak.Client) error {
_, err := kc.client.CreateClient(ctx, kc.getToken(), realm, c)
if isConflict(err) {
log.Printf("Client '%s/%s' already exists, not updated", realm, *c.ClientID)
return nil
}
return err
}
func New(url, user, pass, realm string) (*Keycloak, error) {
kc := &Keycloak{}
kc.client = gocloak.NewClient(url)
kc.user = user
kc.pass = pass
kc.realm = realm
jwt, err := kc.createToken()
kc.accessToken = jwt.AccessToken
kc.validUntil = time.Now().Add(time.Duration(jwt.ExpiresIn) * time.Second)
return kc, err
}
func (kc *Keycloak) getToken() string {
kc.mutex.Lock()
defer kc.mutex.Unlock()
// If token is not valid 30 seconds in the future,
// we need to create a new one
if time.Now().Add(30 * time.Second).After(kc.validUntil) {
jwt, err := kc.createToken()
if err != nil {
log.Fatalf("Valid credentials became invalid: %s", err)
}
kc.accessToken = jwt.AccessToken
kc.validUntil = time.Now().Add(time.Duration(jwt.ExpiresIn) * time.Second)
}
return kc.accessToken
}
func (kc *Keycloak) createToken() (*gocloak.JWT, error) {
token, err := kc.client.LoginAdmin(context.Background(),
kc.user, kc.pass, kc.realm)
if err != nil {
return nil, err
}
return token, nil
}
func isConflict(err error) bool {
if e, ok := err.(*gocloak.APIError); ok {
return (e.Code == 409)
}
return false
}

View file

@ -20,18 +20,26 @@ import (
"context"
"github.com/go-logr/logr"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
keycloakv1alpha1 "git.zom.bi/images/keycloak-operator/api/v1alpha1"
"git.zom.bi/images/keycloak-operator/controllers/keycloak"
)
const (
// FinalizerName is the Name of our finalizer used by this package
FinalizerName = "finalizer.keycloak.bitmask.me"
)
// KeycloakRealmReconciler reconciles a KeycloakRealm object
type KeycloakRealmReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Keycloak *keycloak.Keycloak
Log logr.Logger
Scheme *runtime.Scheme
}
// +kubebuilder:rbac:groups=keycloak.bitmask.me,resources=keycloakrealms,verbs=get;list;watch;create;update;patch;delete
@ -40,17 +48,37 @@ type KeycloakRealmReconciler struct {
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the KeycloakRealm object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.7.0/pkg/reconcile
func (r *KeycloakRealmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = r.Log.WithValues("keycloakrealm", req.NamespacedName)
log := r.Log.WithValues("keycloakrealm", req.NamespacedName)
// your logic here
log.Info("reconciling")
var realm keycloakv1alpha1.KeycloakRealm
if err := r.Get(ctx, req.NamespacedName, &realm); err != nil {
if apierrs.IsNotFound(err) {
log.Info("I would now unregister the realm")
return ctrl.Result{}, nil
}
}
if realm.Status.ID != "" {
// try to get existing realm
log.Info("Would try to fetch the realm by its id.",
"id", realm.Status.ID)
// if found {
log.Info("will act like i found it, updating.")
// update()
return ctrl.Result{}, nil
// }
}
log.Info("Would now create the realm.")
realm.Status.ID = "dummy"
realm.Status.Available = true
r.Status().Update(ctx, &realm)
return ctrl.Result{}, nil
}