1 package grafanadatasource
8 onapv1alpha1 "visualization-operator/pkg/apis/onap/v1alpha1"
10 "k8s.io/apimachinery/pkg/api/errors"
11 "k8s.io/apimachinery/pkg/runtime"
13 "sigs.k8s.io/controller-runtime/pkg/client"
14 "sigs.k8s.io/controller-runtime/pkg/controller"
15 "sigs.k8s.io/controller-runtime/pkg/handler"
16 "sigs.k8s.io/controller-runtime/pkg/manager"
17 "sigs.k8s.io/controller-runtime/pkg/reconcile"
18 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
19 "sigs.k8s.io/controller-runtime/pkg/source"
22 var log = logf.Log.WithName("controller_grafanadatasource")
24 // Add creates a new GrafanaDataSource Controller and adds it to the Manager. The Manager will set fields on the Controller
25 // and Start it when the Manager is Started.
26 func Add(mgr manager.Manager) error {
27 return add(mgr, newReconciler(mgr))
30 // newReconciler returns a new reconcile.Reconciler
31 func newReconciler(mgr manager.Manager) reconcile.Reconciler {
32 return &ReconcileGrafanaDataSource{client: mgr.GetClient(), scheme: mgr.GetScheme()}
35 // add adds a new Controller to mgr with r as the reconcile.Reconciler
36 func add(mgr manager.Manager, r reconcile.Reconciler) error {
37 // Create a new controller
38 c, err := controller.New("grafanadatasource-controller", mgr, controller.Options{Reconciler: r})
43 // Watch for changes to primary resource GrafanaDataSource
44 err = c.Watch(&source.Kind{Type: &onapv1alpha1.GrafanaDataSource{}}, &handler.EnqueueRequestForObject{})
52 // blank assignment to verify that ReconcileGrafanaDataSource implements reconcile.Reconciler
53 var _ reconcile.Reconciler = &ReconcileGrafanaDataSource{}
55 // ReconcileGrafanaDataSource reconciles a GrafanaDataSource object
56 type ReconcileGrafanaDataSource struct {
57 // This client, initialized using mgr.Client() above, is a split client
58 // that reads objects from the cache and writes to the apiserver
60 scheme *runtime.Scheme
63 // Reconcile reads that state of the cluster for a GrafanaDataSource object and makes changes based on the state read
64 // and what is in the GrafanaDataSource.Spec
66 // The Controller will requeue the Request to be processed again if the returned error is non-nil or
67 // Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
68 func (r *ReconcileGrafanaDataSource) Reconcile(request reconcile.Request) (reconcile.Result, error) {
69 reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
70 reqLogger.Info("Reconciling GrafanaDataSource")
72 // Fetch the GrafanaDataSource instance
73 instance := &onapv1alpha1.GrafanaDataSource{}
74 err := r.client.Get(context.TODO(), request.NamespacedName, instance)
76 if errors.IsNotFound(err) {
77 // Request object not found, could have been deleted after reconcile request.
78 // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
79 // Return and don't requeue
80 return reconcile.Result{}, nil
82 // Error reading the object - requeue the request.
84 return reconcile.Result{}, err
87 datasources := instance.Spec.Datasources
88 grafana := instance.Spec.Grafana
90 reqLogger.V(1).Info(" Datasource Name ", "datasources", datasources)
92 //loop through all datasources in the spec
93 for _, datasource := range datasources {
95 //check if datasource exists
96 grafanaURL := grafana["url"] + "/api/datasources/name/" + datasource.Name
97 grafanaUsername := grafana["username"]
98 grafanaPassword := grafana["password"]
100 client := &http.Client{}
101 req, err := http.NewRequest("GET", grafanaURL, nil)
103 reqLogger.Error(err, "GET REQUEST error")
104 return reconcile.Result{}, err
106 req.SetBasicAuth(grafanaUsername, grafanaPassword)
107 getResp, err := client.Do(req)
109 reqLogger.Error(err, "GET RESPONSE error")
110 return reconcile.Result{}, err
113 defer getResp.Body.Close()
115 //add datasource if datasource does not exist already
116 if getResp.StatusCode == http.StatusNotFound {
117 reqLogger.Info("Datasource does not exist, creating one...")
119 if err := createDataSource(grafana, datasource); err != nil {
120 return reconcile.Result{}, err
122 } else if getResp.StatusCode == http.StatusOK {
123 //if datasource already exists
124 reqLogger.V(1).Info("datasource already exists", "datasource", datasource.Name)
126 reqLogger.Error(err, "unknown error", datasource.Name)
130 return reconcile.Result{}, nil
133 func createDataSource(grafana map[string]string, datasource onapv1alpha1.Datasource) error {
134 reqLogger := log.WithValues("Datasource name", datasource.Name, "Datasource URL", datasource.URL)
135 reqLogger.Info("creating datasource")
137 grafanaURL := grafana["url"] + "/api/datasources"
138 grafanaUsername := grafana["username"]
139 grafanaPassword := grafana["password"]
141 client := &http.Client{}
142 postBody, err := json.Marshal(datasource)
144 reqLogger.Error(err, "JSON Marshalling error")
148 req, err := http.NewRequest("POST", grafanaURL, bytes.NewBuffer(postBody))
150 reqLogger.Error(err, "POST REQUEST error")
153 req.Header.Set("Content-Type", "application/json")
154 req.SetBasicAuth(grafanaUsername, grafanaPassword)
155 postResp, err := client.Do(req)
157 reqLogger.Error(err, "POST RESPONSE error")
160 defer req.Body.Close()
162 if postResp.StatusCode == http.StatusOK {
163 reqLogger.Info("Datasource created")