diff --git a/Dockerfile b/Dockerfile index ce816f3..0d58a41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,11 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager # Refer to https://github.com/GoogleContainerTools/distroless for more details FROM gcr.io/distroless/static:nonroot WORKDIR / +ENV \ + KEYCLOAK_URL=http://keycloak \ + KEYCLOAK_USERNAME=keycloak \ + KEYCLOAK_PASSWORD= \ + KEYCLOAK_REALM=master COPY --from=builder /workspace/manager . USER 65532:65532 diff --git a/api/v1alpha1/keycloakrealm_types.go b/api/v1alpha1/keycloakrealm_types.go index c1af23f..caaa312 100644 --- a/api/v1alpha1/keycloakrealm_types.go +++ b/api/v1alpha1/keycloakrealm_types.go @@ -22,23 +22,36 @@ import ( // KeycloakRealmSpec defines the desired state of KeycloakRealm type KeycloakRealmSpec struct { - // Name is the name of the Realm - Name string `json:"realmName"` + // RealmName is the name and public identifier of the Realm + RealmName string `json:"realmName"` - // User readable names - DisplayName *string `json:"displayName,omitempty"` + // Secret containing SMTP configuration + SMTPSecretName string `json:"smtpSecretName,omitempty"` + + // name shown to the user + DisplayName *string `json:"displayName,omitempty"` + // name including HTML tags, or representing a logo image DisplayNameHTML *string `json:"displayHTML,omitempty"` + // the name of the Theme used for the login pages LoginTheme *string `json:"loginTheme,omitempty"` - // Basic realm choices - LoginWithEmailAllowed *bool `json:"loginWithEmailAllowed,omitempty"` - RegistrationAllowed *bool `json:"registrationAllowed,omitempty"` + // if the user can use their email address in the login field + LoginWithEmailAllowed *bool `json:"loginWithEmailAllowed,omitempty"` + // if a user is allowed to self-register via the registration flow + RegistrationAllowed *bool `json:"registrationAllowed,omitempty"` + // if the user should be able to change their username after account creation + EditUsernameAllowed *bool `json:"editUsernameAllowed,omitempty"` + // if the email should be used in place of a selectable user identifier RegistrationEmailAsUsername *bool `json:"registrationEmailAsUsername,omitempty"` - ResetPasswordAllowed *bool `json:"resetPasswordAllowed,omitempty"` - DuplicateEmailsAllowed *bool `json:"duplicateEmailsAllowed,omitempty"` - VerifyEmail *bool `json:"verifyEmail,omitempty"` - RememberMe *bool `json:"rememberMe,omitempty"` + // if the user is allowed to use the reset password flow + ResetPasswordAllowed *bool `json:"resetPasswordAllowed,omitempty"` + // if emails can be registered multiple times + DuplicateEmailsAllowed *bool `json:"duplicateEmailsAllowed,omitempty"` + // if emails should be verified before the user can log into their account + VerifyEmail *bool `json:"verifyEmail,omitempty"` + // if long-lived sessions should be offered to the user upon login + RememberMe *bool `json:"rememberMe,omitempty"` } // KeycloakRealmStatus defines the observed state of KeycloakRealm diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index acc54cd..096741d 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -111,6 +111,11 @@ func (in *KeycloakRealmSpec) DeepCopyInto(out *KeycloakRealmSpec) { *out = new(bool) **out = **in } + if in.EditUsernameAllowed != nil { + in, out := &in.EditUsernameAllowed, &out.EditUsernameAllowed + *out = new(bool) + **out = **in + } if in.RegistrationEmailAsUsername != nil { in, out := &in.RegistrationEmailAsUsername, &out.RegistrationEmailAsUsername *out = new(bool) diff --git a/config/crd/bases/keycloak.bitmask.me_keycloakrealms.yaml b/config/crd/bases/keycloak.bitmask.me_keycloakrealms.yaml new file mode 100644 index 0000000..b9065ae --- /dev/null +++ b/config/crd/bases/keycloak.bitmask.me_keycloakrealms.yaml @@ -0,0 +1,108 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + name: keycloakrealms.keycloak.bitmask.me +spec: + group: keycloak.bitmask.me + names: + kind: KeycloakRealm + listKind: KeycloakRealmList + plural: keycloakrealms + singular: keycloakrealm + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: KeycloakRealm is the Schema for the keycloakrealms API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: KeycloakRealmSpec defines the desired state of KeycloakRealm + properties: + displayHTML: + description: name including HTML tags, or representing a logo image + type: string + displayName: + description: name shown to the user + type: string + duplicateEmailsAllowed: + description: if emails can be registered multiple times + type: boolean + editUsernameAllowed: + description: if the user should be able to change their username after + account creation + type: boolean + loginTheme: + description: the name of the Theme used for the login pages + type: string + loginWithEmailAllowed: + description: if the user can use their email address in the login + field + type: boolean + realmName: + description: RealmName is the name and public identifier of the Realm + type: string + registrationAllowed: + description: if a user is allowed to self-register via the registration + flow + type: boolean + registrationEmailAsUsername: + description: if the email should be used in place of a selectable + user identifier + type: boolean + rememberMe: + description: if long-lived sessions should be offered to the user + upon login + type: boolean + resetPasswordAllowed: + description: if the user is allowed to use the reset password flow + type: boolean + smtpSecretName: + description: Secret containing SMTP configuration + type: string + verifyEmail: + description: if emails should be verified before the user can log + into their account + type: boolean + required: + - realmName + type: object + status: + description: KeycloakRealmStatus defines the observed state of KeycloakRealm + properties: + available: + type: boolean + id: + type: string + required: + - available + - id + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml new file mode 100644 index 0000000..4119a99 --- /dev/null +++ b/config/rbac/role.yaml @@ -0,0 +1,34 @@ + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: manager-role +rules: +- apiGroups: + - keycloak.bitmask.me + resources: + - keycloakrealms + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - keycloak.bitmask.me + resources: + - keycloakrealms/finalizers + verbs: + - update +- apiGroups: + - keycloak.bitmask.me + resources: + - keycloakrealms/status + verbs: + - get + - patch + - update diff --git a/controllers/helpers.go b/controllers/helpers.go new file mode 100644 index 0000000..53ec766 --- /dev/null +++ b/controllers/helpers.go @@ -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 +} diff --git a/controllers/keycloak/keycloak.go b/controllers/keycloak/keycloak.go new file mode 100644 index 0000000..9fa241f --- /dev/null +++ b/controllers/keycloak/keycloak.go @@ -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 +} diff --git a/controllers/keycloakrealm_controller.go b/controllers/keycloakrealm_controller.go index 9e4eafd..81f9faf 100644 --- a/controllers/keycloakrealm_controller.go +++ b/controllers/keycloakrealm_controller.go @@ -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 } diff --git a/go.mod b/go.mod index 44d78ee..e666055 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module git.zom.bi/images/keycloak-operator go 1.15 require ( + github.com/Nerzal/gocloak/v7 v7.11.0 github.com/go-logr/logr v0.3.0 github.com/onsi/ginkgo v1.14.1 github.com/onsi/gomega v1.10.2 diff --git a/go.sum b/go.sum index ed5f385..d1974d6 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,7 @@ cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbf cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363/go.mod h1:WG7q7swWsS2f9PYpt5DoEP/EBYWx8We5UoRltn9vJl8= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= @@ -34,6 +35,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/Nerzal/gocloak/v7 v7.11.0 h1:ab2E55lIMCaUfn47uEHiFhvvMHw+yDHL6Pb+GrM+x04= +github.com/Nerzal/gocloak/v7 v7.11.0/go.mod h1:8fu/dbbIRa1FmLEAOVReZ8PKfbnsl2DwEk6U0giK3KI= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -81,6 +84,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU= +github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -158,6 +163,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-resty/resty/v2 v2.3.0 h1:JOOeAvjSlapTT92p8xiS19Zxev1neGikoHsXJeOq8So= +github.com/go-resty/resty/v2 v2.3.0/go.mod h1:UpN9CgLZNsv4e9XG50UU8xdI0F43UQ4HmxLBDwaroHU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -208,6 +215,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1 h1:A8Yhf6EtqTv9RMsU6MQTyrtV1TjWlR6xU9BsZIwuTCM= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -324,6 +332,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/segmentio/ksuid v1.0.3 h1:FoResxvleQwYiPAVKe1tMUlEirodZqlqglIuFsdDntY= +github.com/segmentio/ksuid v1.0.3/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -352,6 +362,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -397,6 +409,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -443,9 +457,12 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -583,6 +600,7 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -595,6 +613,7 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/main.go b/main.go index 8b32ab8..21560bd 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,7 @@ import ( keycloakv1alpha1 "git.zom.bi/images/keycloak-operator/api/v1alpha1" "git.zom.bi/images/keycloak-operator/controllers" + "git.zom.bi/images/keycloak-operator/controllers/keycloak" // +kubebuilder:scaffold:imports ) @@ -79,10 +80,21 @@ func main() { os.Exit(1) } + kc, err := keycloak.New( + os.Getenv("KEYCLOAK_URL"), + os.Getenv("KEYCLOAK_USERNAME"), + os.Getenv("KEYCLOAK_PASSWORD"), + os.Getenv("KEYCLOAK_REALM")) + if err != nil { + setupLog.Error(err, "unable to connect to keycloak") + os.Exit(1) + } + if err = (&controllers.KeycloakRealmReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("KeycloakRealm"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Keycloak: kc, + Log: ctrl.Log.WithName("controllers").WithName("KeycloakRealm"), + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "KeycloakRealm") os.Exit(1)