Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

Commit

Permalink
Merge 43d7fc1 into d7ddee3
Browse files Browse the repository at this point in the history
  • Loading branch information
pb82 committed Oct 2, 2019
2 parents d7ddee3 + 43d7fc1 commit c1aa0ab
Show file tree
Hide file tree
Showing 31 changed files with 4,206 additions and 247 deletions.
8 changes: 8 additions & 0 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"os"
"runtime"

routev1 "github.com/openshift/api/route/v1"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/rest"
Expand Down Expand Up @@ -122,6 +124,12 @@ func main() {
os.Exit(1)
}

// Setup Scheme for OpenShift routes
if err := routev1.AddToScheme(mgr.GetScheme()); err != nil {
log.Error(err, "")
os.Exit(1)
}

// Setup all Controllers
if err := controller.AddToManager(mgr); err != nil {
log.Error(err, "")
Expand Down
12 changes: 9 additions & 3 deletions deploy/crds/Keycloak.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,16 @@ spec:
type: array
items:
type: string
externalAccess:
type: object
properties:
enabled:
type: boolean
description: 'If enabled the operator will create an Ingress (or a Route on OpenShift) for the Keycloak Service'
status:
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
- name: v1alpha1
served: true
storage: true
5 changes: 3 additions & 2 deletions deploy/examples/keycloak/keycloak.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ kind: Keycloak
metadata:
name: example-keycloak
spec:
# Add fields here
instances: 3
instances: 1
externalAccess:
enabled: True
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/integr8ly/grafana-operator v1.4.0
github.com/onsi/ginkgo v1.10.1 // indirect
github.com/onsi/gomega v1.7.0 // indirect
github.com/openshift/api v3.9.0+incompatible
github.com/operator-framework/operator-sdk v0.10.1-0.20190911145116-334c667503d0
github.com/prometheus/client_golang v1.1.0 // indirect
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
Expand All @@ -29,7 +30,7 @@ require (
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe // indirect
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 // indirect
golang.org/x/tools v0.0.0-20190927052746-69890759d905 // indirect
golang.org/x/tools v0.0.0-20191001123449-8b695b21ef34 // indirect
google.golang.org/api v0.10.0 // indirect
google.golang.org/appengine v1.6.3 // indirect
google.golang.org/genproto v0.0.0-20190925194540-b8fbc687dcfb // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs=
github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
Expand Down Expand Up @@ -605,6 +607,8 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190927052746-69890759d905 h1:OthNz2adqzWs1n8LWLzi4agXuDngecStsR2egYq+JnA=
golang.org/x/tools v0.0.0-20190927052746-69890759d905/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191001123449-8b695b21ef34 h1:ZTe4dkWyFZj1uW5XK3nzq7dq892hc0aPeO3gPb4N8YQ=
golang.org/x/tools v0.0.0-20191001123449-8b695b21ef34/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
Expand Down
13 changes: 9 additions & 4 deletions pkg/apis/keycloak/v1alpha1/keycloak_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ import (
// KeycloakSpec defines the desired state of Keycloak
// +k8s:openapi-gen=true
type KeycloakSpec struct {
ExternalDatabaseSecret string `json:"externalDatabaseSecret,omitempty"`
AdminCredentialSecret string `json:"adminCredentialSecret,omitempty"`
Extensions []string `json:"extensions,omitempty"`
Instances int `json:"instances,omitempty"`
ExternalDatabaseSecret string `json:"externalDatabaseSecret,omitempty"`
AdminCredentialSecret string `json:"adminCredentialSecret,omitempty"`
Extensions []string `json:"extensions,omitempty"`
Instances int `json:"instances,omitempty"`
ExternalAccess KeycloakExternalAccess `json:"externalAccess,omitempty"`
}

type KeycloakExternalAccess struct {
Enabled bool `json:"enabled,omitempty"`
}

// KeycloakStatus defines the observed state of Keycloak
Expand Down
17 changes: 17 additions & 0 deletions pkg/apis/keycloak/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

123 changes: 46 additions & 77 deletions pkg/common/auto_detect.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package common

import (
"fmt"
"time"

"k8s.io/apimachinery/pkg/runtime"

monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1"
integreatlyv1alpha1 "github.com/integr8ly/grafana-operator/pkg/apis/integreatly/v1alpha1"
keycloakv1alpha1 "github.com/keycloak/keycloak-operator/pkg/apis/keycloak/v1alpha1"
i8ly "github.com/integr8ly/grafana-operator/pkg/apis/integreatly/v1alpha1"
kc "github.com/keycloak/keycloak-operator/pkg/apis/keycloak/v1alpha1"
routev1 "github.com/openshift/api/route/v1"
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
"k8s.io/client-go/discovery"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -16,7 +20,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"
)

var logAuto = logf.Log.WithName("autodetect")
var logger = logf.Log.WithName("autodetect")

// Route kind is not provided by the openshift api
const (
RouteKind = "Route"
)

// Background represents a procedure that runs in the background, periodically auto-detecting features
type Background struct {
Expand Down Expand Up @@ -51,7 +60,7 @@ func (b *Background) Start() {
for {
select {
case <-done:
logAuto.Info("finished the first auto-detection")
logger.Info("finished the first auto-detection")
case <-b.ticker.C:
b.autoDetectCapabilities()
}
Expand All @@ -66,93 +75,53 @@ func (b *Background) Stop() {

func (b *Background) autoDetectCapabilities() {
b.detectMonitoringResources()
b.detectRoute()
}

func (b *Background) detectRoute() {
resourceExists, _ := k8sutil.ResourceExists(b.dc, routev1.SchemeGroupVersion.String(), RouteKind)
b.tryWatch(resourceExists, RouteKind, &routev1.Route{})
}

func (b *Background) detectMonitoringResources() {
stateManager := GetStateManager()
// detect the PrometheusRule resource type exist on the cluster
resourceExists, _ := k8sutil.ResourceExists(b.dc, monitoringv1.SchemeGroupVersion.String(), monitoringv1.PrometheusRuleKind)
prometheusRuleExistsState, keyExists := stateManager.GetState(monitoringv1.PrometheusRuleKind).(bool)

// If the resource exists and we have not set the flag. We do not want to set up the watch a second time
if resourceExists && (!keyExists || (keyExists && !prometheusRuleExistsState)) {
stateManager.SetState(monitoringv1.PrometheusRuleKind, true)

err := watchPrometheusRule(b.controller)
if err != nil {
stateManager.SetState(monitoringv1.PrometheusRuleKind, false)
}
logAuto.Info("PrometheusRule resource type found on cluster. Secondary watch setup")
}
b.tryWatch(resourceExists, monitoringv1.PrometheusRuleKind, &monitoringv1.PrometheusRule{})

// detect the ServiceMonitor resource type exist on the cluster
resourceExists, _ = k8sutil.ResourceExists(b.dc, monitoringv1.SchemeGroupVersion.String(), monitoringv1.ServiceMonitorsKind)
serviceMonitorExistsState, keyExists := stateManager.GetState(monitoringv1.ServiceMonitorsKind).(bool)

// If the resource exists and we have not set the flag
if resourceExists && (!keyExists || (keyExists && !serviceMonitorExistsState)) {
stateManager.SetState(monitoringv1.ServiceMonitorsKind, true)

err := watchServiceMonitor(b.controller)
if err != nil {
stateManager.SetState(monitoringv1.ServiceMonitorsKind, false)
}
logAuto.Info("ServiceMonitor resource type found on cluster. Secondary watch setup")
}
b.tryWatch(resourceExists, monitoringv1.ServiceMonitorsKind, &monitoringv1.ServiceMonitor{})

// detect the GrafanaDashboard resource type resourceExists on the cluster
resourceExists, _ = k8sutil.ResourceExists(b.dc, integreatlyv1alpha1.SchemeGroupVersion.String(), integreatlyv1alpha1.GrafanaDashboardKind)
GrafanaDashboardExistsState, keyExists := stateManager.GetState(integreatlyv1alpha1.GrafanaDashboardKind).(bool)

// If the resource exists and we have not set the flag
if resourceExists && (!keyExists || (keyExists && !GrafanaDashboardExistsState)) {
stateManager.SetState(integreatlyv1alpha1.GrafanaDashboardKind, true)

err := watchGrafanaDashboard(b.controller)
if err != nil {
stateManager.SetState(integreatlyv1alpha1.GrafanaDashboardKind, false)
}
logAuto.Info("GrafanaDashboard resource type found on cluster. Secondary watch setup")
}
}

// Setup watch for prometheus rule resource if the resource type exists on the cluster
func watchPrometheusRule(c controller.Controller) error {
// Watch for changes to secondary resource PrometheusRule and requeue the owner Keycloak
err := c.Watch(&source.Kind{Type: &monitoringv1.PrometheusRule{}}, &handler.EnqueueRequestForOwner{
IsController: true,
OwnerType: &keycloakv1alpha1.Keycloak{},
})
if err != nil {
return err
}

return nil
resourceExists, _ = k8sutil.ResourceExists(b.dc, i8ly.SchemeGroupVersion.String(), i8ly.GrafanaDashboardKind)
b.tryWatch(resourceExists, i8ly.GrafanaDashboardKind, &i8ly.GrafanaDashboard{})
}

// Setup watch for service monitor resource if the resource type exists on the cluster
func watchServiceMonitor(c controller.Controller) error {
// Watch for changes to secondary resource ServiceMonitor and requeue the owner Keycloak
err := c.Watch(&source.Kind{Type: &monitoringv1.ServiceMonitor{}}, &handler.EnqueueRequestForOwner{
IsController: true,
OwnerType: &keycloakv1alpha1.Keycloak{},
})
if err != nil {
return err
func (b *Background) tryWatch(resourceExists bool, kind string, o runtime.Object) {
if !resourceExists {
return
}

return nil
}
stateManager := GetStateManager()
watchExists, keyExists := stateManager.GetState(kind).(bool)

// If no key esists yet, but the resource exists, set up a watch
// If not no key exists, but no watch exists yet, set up a watch
if !keyExists || !watchExists {
// Try to set up the actual watch
err := b.controller.Watch(&source.Kind{Type: o}, &handler.EnqueueRequestForOwner{
IsController: true,
OwnerType: &kc.Keycloak{},
})

// Retry on error
if err != nil {
logger.Error(err, "error creating watch")
stateManager.SetState(kind, false)
return
}

// Setup watch for grafana dashboard resource if the resource type exists on the cluster
func watchGrafanaDashboard(c controller.Controller) error {
err := c.Watch(&source.Kind{Type: &integreatlyv1alpha1.GrafanaDashboard{}}, &handler.EnqueueRequestForOwner{
IsController: true,
OwnerType: &keycloakv1alpha1.Keycloak{},
})
if err != nil {
return err
stateManager.SetState(kind, true)
logger.Info(fmt.Sprintf("'%s' type exists, watch created", kind))
}

return nil
}
19 changes: 18 additions & 1 deletion pkg/common/cluster_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package common
import (
"context"
"fmt"
"github.com/keycloak/keycloak-operator/pkg/apis/keycloak/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -24,12 +27,16 @@ type ClusterAction interface {
type ClusterActionRunner struct {
client client.Client
context context.Context
scheme *runtime.Scheme
cr *v1alpha1.Keycloak
}

func NewClusterActionRunner(context context.Context, client client.Client) ActionRunner {
func NewClusterActionRunner(context context.Context, client client.Client, scheme *runtime.Scheme, cr *v1alpha1.Keycloak) ActionRunner {
return &ClusterActionRunner{
client: client,
context: context,
scheme: scheme,
cr: cr,
}
}

Expand All @@ -47,10 +54,20 @@ func (i *ClusterActionRunner) RunAll(desiredState DesiredClusterState) error {
}

func (i *ClusterActionRunner) Create(obj runtime.Object) error {
err := controllerutil.SetControllerReference(i.cr, obj.(v1.Object), i.scheme)
if err != nil {
return err
}

return i.client.Create(i.context, obj)
}

func (i *ClusterActionRunner) Update(obj runtime.Object) error {
err := controllerutil.SetControllerReference(i.cr, obj.(v1.Object), i.scheme)
if err != nil {
return err
}

return i.client.Update(i.context, obj)
}

Expand Down
Loading

0 comments on commit c1aa0ab

Please sign in to comment.