1 package prometheusremoteendpoint
8 onapv1alpha1 "remote-config-operator/pkg/apis/onap/v1alpha1"
10 monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1"
11 logr "github.com/go-logr/logr"
12 corev1 "k8s.io/api/core/v1"
13 "k8s.io/apimachinery/pkg/api/errors"
14 "k8s.io/apimachinery/pkg/runtime"
15 "k8s.io/apimachinery/pkg/types"
16 remoteconfigutils "remote-config-operator/pkg/controller/utils"
17 "sigs.k8s.io/controller-runtime/pkg/client"
18 "sigs.k8s.io/controller-runtime/pkg/controller"
19 "sigs.k8s.io/controller-runtime/pkg/handler"
20 logf "sigs.k8s.io/controller-runtime/pkg/log"
21 "sigs.k8s.io/controller-runtime/pkg/manager"
22 "sigs.k8s.io/controller-runtime/pkg/reconcile"
23 "sigs.k8s.io/controller-runtime/pkg/source"
26 var log = logf.Log.WithName("controller_prometheusremoteendpoint")
28 // Add creates a new PrometheusRemoteEndpoint Controller and adds it to the Manager. The Manager will set fields on the Controller
29 // and Start it when the Manager is Started.
30 func Add(mgr manager.Manager) error {
31 return add(mgr, newReconciler(mgr))
34 // newReconciler returns a new reconcile.Reconciler
35 func newReconciler(mgr manager.Manager) reconcile.Reconciler {
36 return &ReconcilePrometheusRemoteEndpoint{client: mgr.GetClient(), scheme: mgr.GetScheme()}
39 // add adds a new Controller to mgr with r as the reconcile.Reconciler
40 func add(mgr manager.Manager, r reconcile.Reconciler) error {
41 // Create a new controller
42 c, err := controller.New("prometheusremoteendpoint-controller", mgr, controller.Options{Reconciler: r})
47 // Watch for changes to primary resource PrometheusRemoteEndpoint
49 log.V(1).Info("Add watcher for primary resource PrometheusRemoteEndpoint")
50 err = c.Watch(&source.Kind{Type: &onapv1alpha1.PrometheusRemoteEndpoint{}}, &handler.EnqueueRequestForObject{})
55 log.V(1).Info("Add watcher for secondary resource RemoteFilterAction")
56 // TODO(user): Modify this to be the types you create that are owned by the primary resource
57 // Watch for changes to secondary resource Pods and requeue the owner PrometheusRemoteEndpoint
58 err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
60 OwnerType: &onapv1alpha1.PrometheusRemoteEndpoint{},
63 log.Error(err, "Error enqueuing requests due to remoteFilterAction changes")
67 log.Info("Enqueued reconcile requests due to remoteFilterAction changes")
71 // blank assignment to verify that ReconcilePrometheusRemoteEndpoint implements reconcile.Reconciler
72 var _ reconcile.Reconciler = &ReconcilePrometheusRemoteEndpoint{}
74 // ReconcilePrometheusRemoteEndpoint reconciles a PrometheusRemoteEndpoint object
75 type ReconcilePrometheusRemoteEndpoint struct {
76 // This client, initialized using mgr.Client() above, is a split client
77 // that reads objects from the cache and writes to the apiserver
79 scheme *runtime.Scheme
82 // Reconcile reads that state of the cluster for a PrometheusRemoteEndpoint object and makes changes based on the state read
83 // and what is in the PrometheusRemoteEndpoint.Spec
86 // The Controller will requeue the Request to be processed again if the returned error is non-nil or
87 // Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
88 func (r *ReconcilePrometheusRemoteEndpoint) Reconcile(request reconcile.Request) (reconcile.Result, error) {
89 reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
90 reqLogger.Info("Reconciling PrometheusRemoteEndpoint")
92 // Fetch the PrometheusRemoteEndpoint instance
93 instance := &onapv1alpha1.PrometheusRemoteEndpoint{}
94 err := r.client.Get(context.TODO(), request.NamespacedName, instance)
96 if errors.IsNotFound(err) {
97 // Request object not found, could have been deleted after reconcile request.
98 // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
99 // Return and don't requeue
100 reqLogger.Error(err, "PrometheusRemoteEndpoint object not found")
101 return reconcile.Result{}, nil
103 // Error reading the object - requeue the request.
104 reqLogger.Error(err, "Error reading PrometheusRemoteEndpoint object, Requeing ")
105 return reconcile.Result{}, err
108 isBeingDeleted := checkDeletionTimestamp(reqLogger, instance)
110 //Delete Remote write
111 if err := r.processDeletionRequest(reqLogger, instance); err != nil {
112 reqLogger.Error(err, "Error processing deletion request")
113 return reconcile.Result{}, err
115 return reconcile.Result{}, nil
118 //Add finalizer for the CR object
119 if !remoteconfigutils.Contains(instance.GetFinalizers(), remoteconfigutils.RemoteConfigFinalizer) {
120 reqLogger.Info("Adding finalizer for PrometheusRemoteEndpoint")
121 if err := addFinalizer(reqLogger, instance); err != nil {
122 return reconcile.Result{}, err
124 err := r.client.Update(context.TODO(), instance)
126 reqLogger.Error(err, "Unable to update instance")
127 return reconcile.Result{}, err
129 return reconcile.Result{}, nil
132 if err := r.processPatchRequest(reqLogger, instance); err != nil {
133 reqLogger.Error(err, "Error processing request")
134 return reconcile.Result{}, err
136 return reconcile.Result{}, nil
139 func (r *ReconcilePrometheusRemoteEndpoint) processPatchRequest(reqLogger logr.Logger, instance *onapv1alpha1.PrometheusRemoteEndpoint) error {
141 prom := &monitoringv1.Prometheus{}
142 if err1 := r.client.Get(context.TODO(), types.NamespacedName{Namespace: instance.Namespace, Name: instance.ObjectMeta.Labels["app"]}, prom); err1 != nil {
143 reqLogger.Error(err1, "Error getting prometheus")
146 reqLogger.Info("Found prometheus to update")
150 rws := prom.Spec.RemoteWrite
151 adapterURL := instance.Spec.AdapterUrl
154 for i, spec := range rws {
155 if spec.URL == instance.Spec.AdapterUrl {
156 reqLogger.Info("Remote write already exists, updating it")
157 patch, _ = formPatch("replace", strconv.Itoa(i), adapterURL, instance, reqLogger)
164 reqLogger.Info("Remote write does not exist, creating one...")
165 // rwsLength := len(rws)
166 patch, _ = formPatch("add", "-", adapterURL, instance, reqLogger)
168 patchErr := r.client.Patch(context.TODO(), prom, client.ConstantPatch(types.JSONPatchType, patch))
170 reqLogger.Error(patchErr, "Unable to process patch to prometheus")
173 reqLogger.Info("Patch merged")
178 func checkDeletionTimestamp(reqlogger logr.Logger, instance *onapv1alpha1.PrometheusRemoteEndpoint) bool {
179 isMarkedForDeletion := instance.GetDeletionTimestamp() != nil
180 return isMarkedForDeletion
183 func (r *ReconcilePrometheusRemoteEndpoint) processDeletionRequest(reqLogger logr.Logger, instance *onapv1alpha1.PrometheusRemoteEndpoint) error {
184 prom := &monitoringv1.Prometheus{}
185 if err := r.client.Get(context.TODO(), types.NamespacedName{Namespace: instance.Namespace, Name: instance.ObjectMeta.Labels["app"]}, prom); err != nil {
186 reqLogger.Error(err, "Error getting prometheus")
189 reqLogger.Info("Found prometheus to update")
192 adapterURL := instance.Spec.AdapterUrl
194 rws := prom.Spec.RemoteWrite
195 for i, spec := range rws {
196 if spec.URL == instance.Spec.AdapterUrl {
197 reqLogger.Info("Found remote write to be removed, removing it")
198 patch, _ = formPatch("remove", strconv.Itoa(i), adapterURL, instance, reqLogger)
202 patchErr := r.client.Patch(context.TODO(), prom, client.ConstantPatch(types.JSONPatchType, patch))
204 reqLogger.Error(patchErr, "Unable to process patch to prometheus")
207 reqLogger.Info("Patch merged, remote write removed")
209 //remove Finalizer after deletion
210 if remoteconfigutils.Contains(instance.GetFinalizers(), remoteconfigutils.RemoteConfigFinalizer) {
211 if err := removeFinalizer(reqLogger, instance); err != nil {
214 err := r.client.Update(context.TODO(), instance)
216 reqLogger.Error(err, "Unable to update instance")
223 func addFinalizer(reqlogger logr.Logger, instance *onapv1alpha1.PrometheusRemoteEndpoint) error {
224 reqlogger.Info("Adding finalizer for the PrometheusRemoteEndpoint")
225 instance.SetFinalizers(append(instance.GetFinalizers(), remoteconfigutils.RemoteConfigFinalizer))
229 func removeFinalizer(reqlogger logr.Logger, instance *onapv1alpha1.PrometheusRemoteEndpoint) error {
230 reqlogger.Info("Removing finalizer for the PrometheusRemoteEndpoint")
231 instance.SetFinalizers(remoteconfigutils.Remove(instance.GetFinalizers(), remoteconfigutils.RemoteConfigFinalizer))
235 func formPatch(method string, index string, adapterURL string, instance *onapv1alpha1.PrometheusRemoteEndpoint, reqLogger logr.Logger) ([]byte, error) {
237 var mergePatch []byte
238 path := "/spec/remoteWrite/" + index
239 mergePatch, err = json.Marshal(map[string]interface{}{
242 "value": map[string]interface{}{
244 "remoteTimeout": instance.Spec.RemoteTimeout,
248 reqLogger.Error(err, "Unable to form patch")
251 prependMergePatch := append([]byte{91}, mergePatch...)
252 finalMergePatch := append(prependMergePatch, 93)
253 return finalMergePatch, nil