From 5292aebcf442ecaa88c3b20120c0b5a8fdef5c25 Mon Sep 17 00:00:00 2001 From: Peter Braun Date: Tue, 6 Aug 2019 17:58:26 +0200 Subject: [PATCH 1/2] reimport dashboards after operator restart if not already imported --- cmd/manager/main.go | 15 +-- .../v1alpha1/grafanadashboard_types.go | 2 + .../v1alpha1/grafanadatasource_types.go | 2 + pkg/apis/integreatly/v1alpha1/selectors.go | 31 ++++++ pkg/controller/common/controller_config.go | 2 +- pkg/controller/common/kubeHelper.go | 97 ++++++++++++------- pkg/controller/common/resource_states.go | 1 + pkg/controller/grafana/grafana_controller.go | 23 ++--- .../grafanadashboard/dashboard_controller.go | 55 ++++------- .../datasource_controller.go | 10 +- 10 files changed, 140 insertions(+), 98 deletions(-) create mode 100644 pkg/apis/integreatly/v1alpha1/selectors.go diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 357dfc3b2..ff4b027b5 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -4,23 +4,23 @@ import ( "context" "flag" "fmt" - "github.com/integr8ly/grafana-operator/pkg/controller/common" - "github.com/integr8ly/grafana-operator/pkg/controller/grafanadashboard" - "k8s.io/client-go/rest" - "os" - "runtime" - "sigs.k8s.io/controller-runtime/pkg/runtime/signals" - "github.com/integr8ly/grafana-operator/pkg/apis" "github.com/integr8ly/grafana-operator/pkg/controller" + "github.com/integr8ly/grafana-operator/pkg/controller/common" + "github.com/integr8ly/grafana-operator/pkg/controller/grafanadashboard" + "github.com/integr8ly/grafana-operator/version" "github.com/operator-framework/operator-sdk/pkg/k8sutil" "github.com/operator-framework/operator-sdk/pkg/leader" "github.com/operator-framework/operator-sdk/pkg/ready" sdkVersion "github.com/operator-framework/operator-sdk/version" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + "k8s.io/client-go/rest" + "os" + "runtime" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/manager" logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/runtime/signals" ) var log = logf.Log.WithName("cmd") @@ -35,6 +35,7 @@ func printVersion() { log.Info(fmt.Sprintf("Go Version: %s", runtime.Version())) log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)) log.Info(fmt.Sprintf("operator-sdk Version: %v", sdkVersion.Version)) + log.Info(fmt.Sprintf("operator Version: %v", version.Version)) } func init() { diff --git a/pkg/apis/integreatly/v1alpha1/grafanadashboard_types.go b/pkg/apis/integreatly/v1alpha1/grafanadashboard_types.go index 76ac6ad27..b712cde18 100644 --- a/pkg/apis/integreatly/v1alpha1/grafanadashboard_types.go +++ b/pkg/apis/integreatly/v1alpha1/grafanadashboard_types.go @@ -4,6 +4,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const GrafanaDashboardKind = "GrafanaDashboard" + // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. diff --git a/pkg/apis/integreatly/v1alpha1/grafanadatasource_types.go b/pkg/apis/integreatly/v1alpha1/grafanadatasource_types.go index ed880d25a..a9574bd1c 100644 --- a/pkg/apis/integreatly/v1alpha1/grafanadatasource_types.go +++ b/pkg/apis/integreatly/v1alpha1/grafanadatasource_types.go @@ -4,6 +4,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const GrafanaDataSourceKind = "GrafanaDataSource" + // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. diff --git a/pkg/apis/integreatly/v1alpha1/selectors.go b/pkg/apis/integreatly/v1alpha1/selectors.go new file mode 100644 index 000000000..af2fb0002 --- /dev/null +++ b/pkg/apis/integreatly/v1alpha1/selectors.go @@ -0,0 +1,31 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" +) + +func (d *GrafanaDashboard) matchesSelector(s *metav1.LabelSelector) (bool, error) { + selector, err := metav1.LabelSelectorAsSelector(s) + if err != nil { + return false, err + } + + return selector.Empty() || selector.Matches(labels.Set(d.Labels)), nil +} + +// Check if the dashboard matches at least one of the selectors +func (d *GrafanaDashboard) MatchesSelectors(s []*metav1.LabelSelector) (bool, error) { + result := false + + for _, selector := range s { + match, err := d.matchesSelector(selector) + if err != nil { + return false, err + } + + result = result || match + } + + return result, nil +} diff --git a/pkg/controller/common/controller_config.go b/pkg/controller/common/controller_config.go index dcebc22c1..609812b31 100644 --- a/pkg/controller/common/controller_config.go +++ b/pkg/controller/common/controller_config.go @@ -40,7 +40,7 @@ const ( PluginsMinAge = 5 InitContainerName = "grafana-plugins-init" ResourceFinalizerName = "grafana.cleanup" - RequeueDelaySeconds = 10 + RequeueDelay = time.Second * 15 ) type ControllerConfig struct { diff --git a/pkg/controller/common/kubeHelper.go b/pkg/controller/common/kubeHelper.go index f61a22a1a..905dd022a 100644 --- a/pkg/controller/common/kubeHelper.go +++ b/pkg/controller/common/kubeHelper.go @@ -1,6 +1,7 @@ package common import ( + stdErrors "errors" "fmt" "github.com/integr8ly/grafana-operator/pkg/apis/integreatly/v1alpha1" apps "k8s.io/api/apps/v1" @@ -8,14 +9,19 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" "sigs.k8s.io/controller-runtime/pkg/client/config" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" "strings" "time" ) +var log = logf.Log.WithName("kube_helper") + type KubeHelperImpl struct { k8client *kubernetes.Clientset + config *ControllerConfig } func NewKubeHelper() *KubeHelperImpl { @@ -25,32 +31,41 @@ func NewKubeHelper() *KubeHelperImpl { helper := new(KubeHelperImpl) helper.k8client = k8client + helper.config = GetControllerConfig() return helper } -func (h KubeHelperImpl) getConfigMap(namespace, name string) (*v1.ConfigMap, error) { - opts := metav1.GetOptions{} - return h.k8client.CoreV1().ConfigMaps(namespace).Get(name, opts) +func (h KubeHelperImpl) getConfigMapKey(namespace, name string) string { + return fmt.Sprintf("%s_%s", namespace, strings.ToLower(name)) } -func (h KubeHelperImpl) getGrafanaDeployment(namespaceName string) (*apps.Deployment, error) { - opts := metav1.GetOptions{} - return h.k8client.AppsV1().Deployments(namespaceName).Get(GrafanaDeploymentName, opts) +func (h KubeHelperImpl) getConfigMap(name string) (*v1.ConfigMap, error) { + namespace := h.config.GetConfigString(ConfigOperatorNamespace, "") + return h.k8client.CoreV1().ConfigMaps(namespace).Get(name, metav1.GetOptions{}) +} + +func (h KubeHelperImpl) updateConfigMap(c *v1.ConfigMap) error { + namespace := h.config.GetConfigString(ConfigOperatorNamespace, "") + _, err := h.k8client.CoreV1().ConfigMaps(namespace).Update(c) + return err +} + +func (h KubeHelperImpl) getGrafanaDeployment() (*apps.Deployment, error) { + namespace := h.config.GetConfigString(ConfigOperatorNamespace, "") + return h.k8client.AppsV1().Deployments(namespace).Get(GrafanaDeploymentName, metav1.GetOptions{}) } func (h KubeHelperImpl) UpdateGrafanaConfig(config string, cr *v1alpha1.Grafana) error { - configMap, err := h.getConfigMap(cr.Namespace, GrafanaConfigMapName) + configMap, err := h.getConfigMap(GrafanaConfigMapName) if err != nil { return err } - configMap.Data[GrafanaConfigFileName] = config - _, err = h.k8client.CoreV1().ConfigMaps(cr.Namespace).Update(configMap) - return err + return h.updateConfigMap(configMap) } -func (h KubeHelperImpl) UpdateDashboard(ns string, d *v1alpha1.GrafanaDashboard) (bool, error) { - configMap, err := h.getConfigMap(ns, GrafanaDashboardsConfigMapName) +func (h KubeHelperImpl) UpdateDashboard(d *v1alpha1.GrafanaDashboard) (bool, error) { + configMap, err := h.getConfigMap(GrafanaDashboardsConfigMapName) if err != nil { if errors.IsNotFound(err) { return false, nil @@ -60,14 +75,13 @@ func (h KubeHelperImpl) UpdateDashboard(ns string, d *v1alpha1.GrafanaDashboard) // Prefix the dashboard filename with the namespace to allow multiple namespaces // to import the same dashboard - dashboardName := fmt.Sprintf("%s_%s", d.Namespace, d.Spec.Name) - + dashboardName := h.getConfigMapKey(d.Namespace, d.Spec.Name) if configMap.Data == nil { configMap.Data = make(map[string]string) } configMap.Data[dashboardName] = d.Spec.Json - configMap, err = h.k8client.CoreV1().ConfigMaps(ns).Update(configMap) + err = h.updateConfigMap(configMap) if err != nil { return false, err } @@ -75,8 +89,8 @@ func (h KubeHelperImpl) UpdateDashboard(ns string, d *v1alpha1.GrafanaDashboard) return true, nil } -func (h KubeHelperImpl) IsKnownDataSource(ds *v1alpha1.GrafanaDataSource) (bool, error) { - configMap, err := h.getConfigMap(ds.Namespace, GrafanaDatasourcesConfigMapName) +func (h KubeHelperImpl) isKnown(config, namespace, name string) (bool, error) { + configMap, err := h.getConfigMap(config) if err != nil { if errors.IsNotFound(err) { return false, nil @@ -88,14 +102,26 @@ func (h KubeHelperImpl) IsKnownDataSource(ds *v1alpha1.GrafanaDataSource) (bool, return false, nil } - key := fmt.Sprintf("%s_%s", ds.Namespace, strings.ToLower(ds.Spec.Name)) + key := h.getConfigMapKey(namespace, name) _, found := configMap.Data[key] - return found, nil } +func (h KubeHelperImpl) IsKnown(kind string, o runtime.Object) (bool, error) { + switch kind { + case v1alpha1.GrafanaDashboardKind: + d := o.(*v1alpha1.GrafanaDashboard) + return h.isKnown(GrafanaDashboardsConfigMapName, d.Namespace, d.Spec.Name) + case v1alpha1.GrafanaDataSourceKind: + d := o.(*v1alpha1.GrafanaDataSource) + return h.isKnown(GrafanaDatasourcesConfigMapName, d.Namespace, d.Spec.Name) + default: + return false, stdErrors.New(fmt.Sprintf("unknown kind '%v'", kind)) + } +} + func (h KubeHelperImpl) UpdateDataSources(name, namespace, ds string) (bool, error) { - configMap, err := h.getConfigMap(namespace, GrafanaDatasourcesConfigMapName) + configMap, err := h.getConfigMap(GrafanaDatasourcesConfigMapName) if err != nil { if errors.IsNotFound(err) { return false, nil @@ -105,14 +131,14 @@ func (h KubeHelperImpl) UpdateDataSources(name, namespace, ds string) (bool, err // Prefix the data source filename with the namespace to allow multiple namespaces // to import the same dashboard - key := fmt.Sprintf("%s_%s", namespace, strings.ToLower(name)) + key := h.getConfigMapKey(namespace, name) if configMap.Data == nil { configMap.Data = make(map[string]string) } configMap.Data[key] = ds - configMap, err = h.k8client.CoreV1().ConfigMaps(namespace).Update(configMap) + err = h.updateConfigMap(configMap) if err != nil { return false, err } @@ -120,7 +146,7 @@ func (h KubeHelperImpl) UpdateDataSources(name, namespace, ds string) (bool, err } func (h KubeHelperImpl) DeleteDataSources(name, namespace string) error { - configMap, err := h.getConfigMap(namespace, GrafanaDatasourcesConfigMapName) + configMap, err := h.getConfigMap(GrafanaDatasourcesConfigMapName) if err != nil { // Grafana may already be uninstalled if errors.IsNotFound(err) { @@ -131,7 +157,7 @@ func (h KubeHelperImpl) DeleteDataSources(name, namespace string) error { // Prefix the dashboard filename with the namespace to allow multiple namespaces // to import the same dashboard - key := fmt.Sprintf("%s_%s", namespace, strings.ToLower(name)) + key := h.getConfigMapKey(namespace, name) if configMap.Data == nil { return nil @@ -143,12 +169,12 @@ func (h KubeHelperImpl) DeleteDataSources(name, namespace string) error { } delete(configMap.Data, key) - configMap, err = h.k8client.CoreV1().ConfigMaps(namespace).Update(configMap) + err = h.updateConfigMap(configMap) return err } -func (h KubeHelperImpl) DeleteDashboard(monitoringNamespace string, dashboardNamespace string, dashboard *v1alpha1.GrafanaDashboard) error { - configMap, err := h.getConfigMap(monitoringNamespace, GrafanaDashboardsConfigMapName) +func (h KubeHelperImpl) DeleteDashboard(d *v1alpha1.GrafanaDashboard) error { + configMap, err := h.getConfigMap(GrafanaDashboardsConfigMapName) if err != nil { if errors.IsNotFound(err) { // Grafana may already be uninstalled @@ -157,10 +183,7 @@ func (h KubeHelperImpl) DeleteDashboard(monitoringNamespace string, dashboardNam return err } - // Prefix the dashboard filename with the namespace to allow multiple namespaces - // to import the same dashboard - dashboardName := fmt.Sprintf("%s_%s", dashboardNamespace, dashboard.Spec.Name) - + dashboardName := h.getConfigMapKey(d.Namespace, d.Spec.Name) if configMap.Data == nil { return nil } @@ -171,7 +194,7 @@ func (h KubeHelperImpl) DeleteDashboard(monitoringNamespace string, dashboardNam } delete(configMap.Data, dashboardName) - configMap, err = h.k8client.CoreV1().ConfigMaps(monitoringNamespace).Update(configMap) + err = h.updateConfigMap(configMap) if err != nil { return err } @@ -199,8 +222,10 @@ func (h KubeHelperImpl) getGrafanaPod(namespaceName string) (*core.Pod, error) { return &pods.Items[0], nil } -func (h KubeHelperImpl) UpdateGrafanaDeployment(monitoringNamespace string, newEnv string) error { - deployment, err := h.getGrafanaDeployment(monitoringNamespace) +func (h KubeHelperImpl) UpdateGrafanaDeployment(newEnv string) error { + monitoringNamespace := h.config.GetConfigString(ConfigOperatorNamespace, "") + deployment, err := h.getGrafanaDeployment() + if err != nil { return err } @@ -228,8 +253,10 @@ func (h KubeHelperImpl) UpdateGrafanaDeployment(monitoringNamespace string, newE return nil } -func (h KubeHelperImpl) RestartGrafana(monitoringNamespace string) error { +func (h KubeHelperImpl) RestartGrafana() error { + monitoringNamespace := h.config.GetConfigString(ConfigOperatorNamespace, "") pod, err := h.getGrafanaPod(monitoringNamespace) + if err != nil { if errors.IsNotFound(err) { // No need to restart if grafana has not yet been deployed diff --git a/pkg/controller/common/resource_states.go b/pkg/controller/common/resource_states.go index d3f9adfd2..7a914a4ed 100644 --- a/pkg/controller/common/resource_states.go +++ b/pkg/controller/common/resource_states.go @@ -4,4 +4,5 @@ const ( StatusResourceUninitialized int = iota StatusResourceSetFinalizer StatusResourceCreated + StatusResourceOrphaned ) diff --git a/pkg/controller/grafana/grafana_controller.go b/pkg/controller/grafana/grafana_controller.go index dfd82c7ca..956f0f38b 100644 --- a/pkg/controller/grafana/grafana_controller.go +++ b/pkg/controller/grafana/grafana_controller.go @@ -3,19 +3,17 @@ package grafana import ( "context" "fmt" + i8ly "github.com/integr8ly/grafana-operator/pkg/apis/integreatly/v1alpha1" "github.com/integr8ly/grafana-operator/pkg/controller/common" core "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "time" - - i8ly "github.com/integr8ly/grafana-operator/pkg/apis/integreatly/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -32,7 +30,6 @@ const ( PhaseReconcile ) -const ReconcilePauseSeconds = 5 const OpenShiftOAuthRedirect = "serviceaccounts.openshift.io/oauth-redirectreference.primary" /** @@ -139,14 +136,14 @@ func (r *ReconcileGrafana) ReconcileGrafana(cr *i8ly.Grafana) (reconcile.Result, } // Grafana needs to be restarted after a config change - err = r.helper.RestartGrafana(cr.Namespace) + err = r.helper.RestartGrafana() if err != nil { return reconcile.Result{}, err } log.Info("grafana restarted due to config change") // Skip plugins reconciliation while grafana is restarting - return reconcile.Result{RequeueAfter: time.Second * ReconcilePauseSeconds}, err + return reconcile.Result{RequeueAfter: common.RequeueDelay}, err } // Plugins updated? @@ -155,7 +152,7 @@ func (r *ReconcileGrafana) ReconcileGrafana(cr *i8ly.Grafana) (reconcile.Result, return reconcile.Result{}, err } - return reconcile.Result{RequeueAfter: time.Second * ReconcilePauseSeconds}, err + return reconcile.Result{RequeueAfter: common.RequeueDelay}, err } func (r *ReconcileGrafana) ReconcileDashboardPlugins(cr *i8ly.Grafana) error { @@ -179,7 +176,7 @@ func (r *ReconcileGrafana) ReconcileDashboardPlugins(cr *i8ly.Grafana) error { // Update the dashboards that had their plugins modified // to let the owners know about the status - err := r.UpdateDashboardMessages(filteredPlugins) + err := r.updateDashboardMessages(filteredPlugins) if err != nil { return err } @@ -212,11 +209,11 @@ func (r *ReconcileGrafana) ReconcilePlugins(cr *i8ly.Grafana, plugins []i8ly.Gra } newEnv := r.plugins.BuildEnv(cr) - err = r.helper.UpdateGrafanaDeployment(cr.Namespace, newEnv) + err = r.helper.UpdateGrafanaDeployment(newEnv) return err } -func (r *ReconcileGrafana) UpdateDashboardMessages(plugins i8ly.PluginList) error { +func (r *ReconcileGrafana) updateDashboardMessages(plugins i8ly.PluginList) error { for _, plugin := range plugins { err := r.client.Update(context.TODO(), plugin.Origin) if err != nil { diff --git a/pkg/controller/grafanadashboard/dashboard_controller.go b/pkg/controller/grafanadashboard/dashboard_controller.go index 99f812091..efceedf9e 100644 --- a/pkg/controller/grafanadashboard/dashboard_controller.go +++ b/pkg/controller/grafanadashboard/dashboard_controller.go @@ -7,13 +7,10 @@ import ( "fmt" i8ly "github.com/integr8ly/grafana-operator/pkg/apis/integreatly/v1alpha1" "github.com/integr8ly/grafana-operator/pkg/controller/common" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/util/json" - "time" - "k8s.io/apimachinery/pkg/api/errors" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/json" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -75,36 +72,12 @@ type ReconcileGrafanaDashboard struct { helper *common.KubeHelperImpl } -func (r *ReconcileGrafanaDashboard) matchesSelector(d *i8ly.GrafanaDashboard, s *v1.LabelSelector) (bool, error) { - selector, err := v1.LabelSelectorAsSelector(s) - if err != nil { - return false, err - } - - return selector.Empty() || selector.Matches(labels.Set(d.Labels)), nil -} - -func (r *ReconcileGrafanaDashboard) matchesSelectors(d *i8ly.GrafanaDashboard, s []*v1.LabelSelector) (bool, error) { - result := false - - for _, selector := range s { - match, err := r.matchesSelector(d, selector) - if err != nil { - return false, err - } - - result = result || match - } - - return result, nil -} - // The Controller will requeue the Request to be processed again if the returned error is non-nil or // Result.Requeue is true, otherwise upon completion it will remove the work from the queue. func (r *ReconcileGrafanaDashboard) Reconcile(request reconcile.Request) (reconcile.Result, error) { dashboardLabelSelectors := r.config.GetConfigItem(common.ConfigDashboardLabelSelector, nil) if dashboardLabelSelectors == nil { - return reconcile.Result{RequeueAfter: time.Second * 10}, nil + return reconcile.Result{RequeueAfter: common.RequeueDelay}, nil } // Fetch the GrafanaDashboard instance @@ -122,7 +95,7 @@ func (r *ReconcileGrafanaDashboard) Reconcile(request reconcile.Request) (reconc } cr := instance.DeepCopy() - if match, err := r.matchesSelectors(cr, dashboardLabelSelectors.([]*v1.LabelSelector)); err != nil { + if match, err := cr.MatchesSelectors(dashboardLabelSelectors.([]*v1.LabelSelector)); err != nil { return reconcile.Result{}, err } else if !match { log.Info(fmt.Sprintf("found dashboard '%s/%s' but labels do not match", cr.Namespace, cr.Name)) @@ -156,8 +129,18 @@ func (r *ReconcileGrafanaDashboard) Reconcile(request reconcile.Request) (reconc func (r *ReconcileGrafanaDashboard) checkPrerequisites(d *i8ly.GrafanaDashboard) bool { changed, hash := r.hasDashboardChanged(d) if !changed { - log.Info("dashboard reconciled but no changes") - return false + known, err := r.helper.IsKnown(i8ly.GrafanaDashboardKind, d) + if err != nil { + log.Error(err, "error checking dashboard status") + return false + } + + // If the dashboard is known and unchanged we don't have to + // import it again + if known { + log.Info("dashboard reconciled but no changes") + return false + } } d.Status.LastConfig = hash @@ -196,13 +179,13 @@ func (r *ReconcileGrafanaDashboard) importDashboard(d *i8ly.GrafanaDashboard) (r return reconcile.Result{Requeue: false}, nil } - updated, err := r.helper.UpdateDashboard(operatorNamespace, d) + updated, err := r.helper.UpdateDashboard(d) if err != nil { return reconcile.Result{}, err } if !updated { - return reconcile.Result{RequeueAfter: time.Second * common.RequeueDelaySeconds}, err + return reconcile.Result{RequeueAfter: common.RequeueDelay}, err } // Reconcile dashboard plugins @@ -226,7 +209,7 @@ func (r *ReconcileGrafanaDashboard) deleteDashboard(d *i8ly.GrafanaDashboard) (r return reconcile.Result{}, defaultErrors.New("no monitoring namespace set") } - err := r.helper.DeleteDashboard(operatorNamespace, d.Namespace, d) + err := r.helper.DeleteDashboard(d) if err == nil { log.Info(fmt.Sprintf("dashboard '%s/%s' deleted", d.Namespace, d.Spec.Name)) } diff --git a/pkg/controller/grafanadatasource/datasource_controller.go b/pkg/controller/grafanadatasource/datasource_controller.go index 7d5d4ac0f..7ab67cd19 100644 --- a/pkg/controller/grafanadatasource/datasource_controller.go +++ b/pkg/controller/grafanadatasource/datasource_controller.go @@ -7,8 +7,6 @@ import ( "github.com/ghodss/yaml" i8ly "github.com/integr8ly/grafana-operator/pkg/apis/integreatly/v1alpha1" "github.com/integr8ly/grafana-operator/pkg/controller/common" - "time" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -120,7 +118,7 @@ func (r *ReconcileGrafanaDataSource) reconcileDatasource(cr *i8ly.GrafanaDataSou return reconcile.Result{}, err } - known, err := r.helper.IsKnownDataSource(cr) + known, err := r.helper.IsKnown(i8ly.GrafanaDataSourceKind, cr) if err != nil { return reconcile.Result{}, err } @@ -142,10 +140,10 @@ func (r *ReconcileGrafanaDataSource) reconcileDatasource(cr *i8ly.GrafanaDataSou } if !updated { - return reconcile.Result{RequeueAfter: time.Second * common.RequeueDelaySeconds}, err + return reconcile.Result{RequeueAfter: common.RequeueDelay}, err } - err = r.helper.RestartGrafana(cr.Namespace) + err = r.helper.RestartGrafana() if err != nil { log.Error(err, "error restarting grafana") } @@ -171,7 +169,7 @@ func (r *ReconcileGrafanaDataSource) DeleteDatasource(cr *i8ly.GrafanaDataSource log.Error(err, "error removing finalizer") } - err = r.helper.RestartGrafana(cr.Namespace) + err = r.helper.RestartGrafana() if err != nil { log.Error(err, "error restarting grafana") } From b84ccbdf901bbf932160c1357f11f967653c0baa Mon Sep 17 00:00:00 2001 From: Peter Braun Date: Tue, 6 Aug 2019 18:11:44 +0200 Subject: [PATCH 2/2] detect resources from a previous installation --- pkg/controller/grafanadashboard/dashboard_controller.go | 9 +++++++-- .../grafanadatasource/datasource_controller.go | 8 +++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pkg/controller/grafanadashboard/dashboard_controller.go b/pkg/controller/grafanadashboard/dashboard_controller.go index efceedf9e..62a819cb6 100644 --- a/pkg/controller/grafanadashboard/dashboard_controller.go +++ b/pkg/controller/grafanadashboard/dashboard_controller.go @@ -120,7 +120,13 @@ func (r *ReconcileGrafanaDashboard) Reconcile(request reconcile.Request) (reconc } case common.StatusResourceCreated: // Import / update dashboard - return r.importDashboard(cr) + res, err := r.importDashboard(cr) + + // Requeue periodically to find dashboards that have not been updated + // but are not yet imported (can happen if Grafana is uninstalled and + // then reinstalled without an Operator restart + res.RequeueAfter = common.RequeueDelay + return res, err default: return reconcile.Result{}, nil } @@ -242,7 +248,6 @@ func (r *ReconcileGrafanaDashboard) isJsonValid(cr *i8ly.GrafanaDashboard) (bool var js map[string]interface{} err := json.Unmarshal([]byte(cr.Spec.Json), &js) return err == nil, err - } func (r *ReconcileGrafanaDashboard) hasDashboardChanged(cr *i8ly.GrafanaDashboard) (bool, string) { diff --git a/pkg/controller/grafanadatasource/datasource_controller.go b/pkg/controller/grafanadatasource/datasource_controller.go index 7ab67cd19..5712ff5d8 100644 --- a/pkg/controller/grafanadatasource/datasource_controller.go +++ b/pkg/controller/grafanadatasource/datasource_controller.go @@ -105,7 +105,13 @@ func (r *ReconcileGrafanaDataSource) Reconcile(request reconcile.Request) (recon return r.setFinalizer(cr) } case common.StatusResourceCreated: - return r.reconcileDatasource(cr) + res, err := r.reconcileDatasource(cr) + + // Requeue periodically to find datasources that have not been updated + // but are not yet imported (can happen if Grafana is uninstalled and + // then reinstalled without an Operator restart + res.RequeueAfter = common.RequeueDelay + return res, err default: return reconcile.Result{}, nil }