gokuberneteskubernetes-operator

"error": "no kind is registered for the type v1.ServiceMonitor in scheme \"pkg/runtime/scheme.go:100\""}


I created an operator for my application and want to create a service monitor for it. The Prometheus operator was created. The monitoring Prometheus library was imported and the service monitor CRD was created in my k8s cluster. Here is the Go code for this object:

package controllers

import (
    "context"
    "fmt"

    appsv1alpha1 "k8s-operator/api/v1alpha1"

    monitoring "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
    "gopkg.in/yaml.v2"
    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/types"
    "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    "sigs.k8s.io/controller-runtime/pkg/reconcile"
)

// ensureSvcMonitor ensures SvcMonitor is Running in a namespace.
func (r *MyappReconciler) ensureSvcMonitor(request reconcile.Request,
    instance *appsv1alpha1.Myapp,
    svcmonitor *monitoring.ServiceMonitor,
) (*reconcile.Result, error) {

    // See if SvcMonitor already exists and create if it doesn't
    found := &monitoring.ServiceMonitor{}
    err := r.Get(context.TODO(), types.NamespacedName{
        Name:      svcmonitor.Name,
        Namespace: instance.Namespace,
    }, found)
    if err != nil && errors.IsNotFound(err) {

        // Create the SvcMonitor
        err = r.Create(context.TODO(), svcmonitor)

        if err != nil {
            // SvcMonitor creation failed
            return &reconcile.Result{}, err
        } else {
            // SvcMonitor creation was successful
            return nil, nil
        }
    } else if err != nil {
        // Error that isn't due to the SvcMonitor not existing
        return &reconcile.Result{}, err
    }

    return nil, nil
}

// backendSvcMonitor is a code for creating a SvcMonitor
func (r *MyappReconciler) backendSvcMonitor(v *appsv1alpha1.Myapp) *monitoring.ServiceMonitor {

    svcmonitor := &monitoring.ServiceMonitor{
        TypeMeta: metav1.TypeMeta{
            Kind:       "ServiceMonitor",
            APIVersion: "monitoring.coreos.com/v1",
        },
        ObjectMeta: metav1.ObjectMeta{
            Name:      v.Spec.Name + "-svcmonitor",
            Namespace: v.Namespace},
        Spec: monitoring.ServiceMonitorSpec{
            Endpoints: []monitoring.Endpoint{{
                Port: v.Spec.Name,
            }},
            Selector: metav1.LabelSelector{
                MatchLabels: labels(v),
            },
        },
    }

    controllerutil.SetControllerReference(v, svcmonitor, r.Scheme)
    yamlData, _ := yaml.Marshal(&svcmonitor)
    fmt.Println(string(yamlData))
    return svcmonitor
}

Here is the part which I call these function to create this object in my controller:

if instance.Spec.Servicemonitorenable {
        result, err = r.ensureSvcMonitor(req, instance, r.backendSvcMonitor(instance))
        if result != nil {
            log.Error(err, "Servicemonitor Not ready")
            return *result, err
        }
    }

But when I create the custom resource instance I get this error:

"error": "no kind is registered for the type v1.ServiceMonitor in scheme \"pkg/runtime/scheme.go:100\""}

Solution

  • In your main.go, you need to add monitoring/v1 to the scheme injected into controller-runtime i.e.:

    // main.go
    package main
    
    import (
        "os"
        ctrl "sigs.k8s.io/controller-runtime"
        monitoring "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
        "k8s.io/apimachinery/pkg/runtime"
    )
    
    var (
        scheme = runtime.NewScheme()
    )
    
    func init() {
        monitoring.AddToScheme(scheme)
    }
    
    func main() {
        mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
            Scheme: scheme,
            // ... other options here
        })
    
        // Start Manager
        if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
            os.Exit(1)
        }
    }