Unverified Commit 49d0f746 authored by OpenShift Merge Robot's avatar OpenShift Merge Robot Committed by GitHub
Browse files

Merge pull request #290 from ironcladlou/bz-1740258

Bug 1740258: fix prometheus integration for multiple ingresscontrollers
parents 6a306dbf b4e2430b
......@@ -38,6 +38,7 @@ rules:
verbs:
- create
- get
- update
- apiGroups:
- rbac.authorization.k8s.io
......
......@@ -484,7 +484,7 @@ func (r *reconciler) ensureMetricsIntegration(ci *operatorv1.IngressController,
log.Info("created router metrics role binding", "name", mrb.Name)
}
if _, err := r.ensureServiceMonitor(ci, svc, deploymentRef); err != nil {
if _, _, err := r.ensureServiceMonitor(ci, svc, deploymentRef); err != nil {
return fmt.Errorf("failed to ensure servicemonitor for %s: %v", ci.Name, err)
}
......
......@@ -3,11 +3,13 @@ package controller
import (
"context"
"fmt"
"reflect"
operatorv1 "github.com/openshift/api/operator/v1"
corev1 "k8s.io/api/core/v1"
"github.com/openshift/cluster-ingress-operator/pkg/manifests"
operatorclient "github.com/openshift/cluster-ingress-operator/pkg/operator/client"
"k8s.io/apimachinery/pkg/api/errors"
......@@ -18,22 +20,30 @@ import (
"k8s.io/apimachinery/pkg/types"
)
func (r *reconciler) ensureServiceMonitor(ci *operatorv1.IngressController, svc *corev1.Service, deploymentRef metav1.OwnerReference) (*unstructured.Unstructured, error) {
func (r *reconciler) ensureServiceMonitor(ci *operatorv1.IngressController, svc *corev1.Service, deploymentRef metav1.OwnerReference) (bool, *unstructured.Unstructured, error) {
desired := desiredServiceMonitor(ci, svc, deploymentRef)
current, err := r.currentServiceMonitor(ci)
haveSM, current, err := r.currentServiceMonitor(ci)
if err != nil {
return nil, err
return false, nil, err
}
if desired != nil && current == nil {
if err := r.client.Create(context.TODO(), desired); err != nil {
return nil, fmt.Errorf("failed to create servicemonitor %s/%s: %v", desired.GetNamespace(), desired.GetName(), err)
switch {
case !haveSM:
if created, err := r.createServiceMonitor(desired); err != nil {
return false, nil, fmt.Errorf("failed to create servicemonitor %s/%s: %v", desired.GetNamespace(), desired.GetName(), err)
} else if created {
log.Info("created servicemonitor", "namespace", desired.GetNamespace(), "name", desired.GetName())
}
case haveSM:
if updated, err := r.updateServiceMonitor(current, desired); err != nil {
return true, nil, fmt.Errorf("failed to update servicemonitor %s/%s: %v", desired.GetNamespace(), desired.GetName(), err)
} else if updated {
log.Info("updated servicemonitor", "namespace", desired.GetNamespace(), "name", desired.GetName())
}
log.Info("created servicemonitor", "namespace", desired.GetNamespace(), "name", desired.GetName())
return desired, nil
}
return current, nil
return r.currentServiceMonitor(ci)
}
func serviceMonitorName(ci *operatorv1.IngressController) types.NamespacedName {
......@@ -54,9 +64,22 @@ func desiredServiceMonitor(ci *operatorv1.IngressController, svc *corev1.Service
"openshift-ingress",
},
},
"selector": map[string]interface{}{},
"endpoints": []map[string]interface{}{
{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
manifests.OwningIngressControllerLabel: ci.Name,
},
},
// It is important to use the type []interface{}
// for the "endpoints" field. Using
// []map[string]interface{} causes at least two
// problems: first, DeepCopy will fail with
// "cannot deep copy []map[string]interface {}";
// second, the API returns an object that uses
// type []interface{} for this field, so
// DeepEqual against an API object will always
// return false.
"endpoints": []interface{}{
map[string]interface{}{
"bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token",
"interval": "30s",
"port": "metrics",
......@@ -80,7 +103,10 @@ func desiredServiceMonitor(ci *operatorv1.IngressController, svc *corev1.Service
return sm
}
func (r *reconciler) currentServiceMonitor(ci *operatorv1.IngressController) (*unstructured.Unstructured, error) {
// currentServiceMonitor returns the current servicemonitor. Returns a Boolean
// indicating whether the servicemonitor existed, the servicemonitor if it did
// exist, and an error value.
func (r *reconciler) currentServiceMonitor(ci *operatorv1.IngressController) (bool, *unstructured.Unstructured, error) {
sm := &unstructured.Unstructured{}
sm.SetGroupVersionKind(schema.GroupVersionKind{
Group: "monitoring.coreos.com",
......@@ -92,20 +118,55 @@ func (r *reconciler) currentServiceMonitor(ci *operatorv1.IngressController) (*u
// Refresh kube client with latest rest scheme/mapper.
kClient, err := operatorclient.NewClient(r.KubeConfig)
if err != nil {
return nil, fmt.Errorf("failed to create kube client: %v", err)
return false, nil, fmt.Errorf("failed to create kube client: %v", err)
}
r.client = kClient
err = r.client.Get(context.TODO(), serviceMonitorName(ci), sm)
if err == nil {
return sm, nil
return true, sm, nil
}
}
if errors.IsNotFound(err) {
return nil, nil
return false, nil, nil
}
return nil, err
return false, nil, err
}
return true, sm, nil
}
// createServiceMonitor creates a servicemonitor. Returns a Boolean indicating
// whether the servicemonitor was created, and an error value.
func (r *reconciler) createServiceMonitor(sm *unstructured.Unstructured) (bool, error) {
if err := r.client.Create(context.TODO(), sm); err != nil {
return false, err
}
return true, nil
}
// updateServiceMonitor updates a servicemonitor. Returns a Boolean indicating
// whether the servicemonitor was updated, and an error value.
func (r *reconciler) updateServiceMonitor(current, desired *unstructured.Unstructured) (bool, error) {
changed, updated := serviceMonitorChanged(current, desired)
if !changed {
return false, nil
}
if err := r.client.Update(context.TODO(), updated); err != nil {
return false, err
}
return sm, nil
return true, nil
}
// serviceMonitorChanged checks if current servicemonitor spec matches the
// expected spec and if not returns an updated one.
func serviceMonitorChanged(current, expected *unstructured.Unstructured) (bool, *unstructured.Unstructured) {
if reflect.DeepEqual(current.Object["spec"], expected.Object["spec"]) {
return false, nil
}
updated := current.DeepCopy()
updated.Object["spec"] = expected.Object["spec"]
return true, updated
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment