<p>I'm developing a kubernetes operator that represents a very simple api and a controller.
I would like to maximize the number of the CustomResources those could belonging to the specific CustomResourceDefinition that the operator defines. (As specially I would like to allow just one CR, if it is already defined, the operator should throw an error message and skip reconciling it.)
If I generate the api, there is a KindList struct default generated, and if I understand correctly, it should keep track of the CRs already defined for my CRD. It is also added to the scheme by default. See the example from kubebuilder documentation:</p>
<pre><code>//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// CronJob is the Schema for the cronjobs API
type CronJob struct {
    metav1.TypeMeta   `json:&quot;,inline&quot;`
    metav1.ObjectMeta `json:&quot;metadata,omitempty&quot;`

    Spec   CronJobSpec   `json:&quot;spec,omitempty&quot;`
    Status CronJobStatus `json:&quot;status,omitempty&quot;`
}

//+kubebuilder:object:root=true

// CronJobList contains a list of CronJob
type CronJobList struct {
    metav1.TypeMeta `json:&quot;,inline&quot;`
    metav1.ListMeta `json:&quot;metadata,omitempty&quot;`
    Items           []CronJob `json:&quot;items&quot;`
}

func init() {
    SchemeBuilder.Register(&amp;CronJob{}, &amp;CronJobList{})
}
</code></pre>
<p>Unfortunately, I can not find out how to access this List from the controller. I have tried like this, but r.Get can not accept cacheList:</p>
<pre><code>cronjob/cronjob_controller.go

package controllers

import (
    &quot;context&quot;

    &quot;k8s.io/apimachinery/pkg/runtime&quot;
    ctrl &quot;sigs.k8s.io/controller-runtime&quot;
    &quot;sigs.k8s.io/controller-runtime/pkg/client&quot;
    &quot;sigs.k8s.io/controller-runtime/pkg/log&quot;

    cronjobv1alpha1 &quot;github.com/example/cronjob-operator/api/v1alpha1&quot;
)

func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    _ = log.FromContext(ctx)

    // TODO(user): your logic here

    cronjob := cronjobv1alpha1.Memcached{}
    if err := r.Get(ctx, req.NamespacedName, &amp;cronjob); err != nil {
        return ctrl.Result{}, err
    }

    cronjobList := cachev1alpha1.MemcachedList{}
    if err := r.Get(ctx, req.NamespacedName, &amp;cronjobList); err != nil {
        return ctrl.Result{}, err
    }

    return ctrl.Result{}, nil
}

</code></pre>
<p>If I get the list, I could validate the length of it, and do or skip the reconcile.</p>
<p>Is it even a correct approach? Is there a better way to achieve my goal? Should I create a webhook instead?</p>

<p>Assuming you are using the default <code>sigs.k8s.io/controller-runtime/pkg/client</code>'s <code>client.Client</code>, you get access to the <code>List()</code> function.</p>
<p>In your case <code>r.List(...)</code>.</p>
<h2>Usage:</h2>
<h3>case 1: list by label</h3>
<pre class="lang-golang prettyprint-override"><code>func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    cronjobList := cronjobv1alpha1.CronJobList{}
    err = r.List(ctx, &amp;cronjobList, client.MatchingLabels{&quot;foo&quot;: &quot;bar&quot;})
    if err != nil {
        return ctrl.Result{}, err
    }
}
</code></pre>
<h3>case 2: list all in namespace</h3>
<pre class="lang-golang prettyprint-override"><code>func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    cronjobList := cronjobv1alpha1.CronJobList{}
    err = r.List(ctx, &amp;cronjobList, client.InNamespace(&quot;default&quot;))
    if err != nil {
        return ctrl.Result{}, err
    }
}
</code></pre>
<h3>case 3: list by field i.e. metadata.name</h3>
<pre class="lang-golang prettyprint-override"><code>// in your Reconciler Setup function create an index
func SetupWithManager(mgr ctrl.Manager) error {
    r := &amp;CronJobReconciler{
        Client:   mgr.GetClient(),
    }
    mgr.GetFieldIndexer().IndexField(context.TODO(), &amp;cronjobv1alpha1.CronJob{}, &quot;metadata.name&quot;, NameIndexer)

    return ctrl.NewControllerManagedBy(mgr).
        For(&amp;cronjobv1alpha1.CronJob{}).
        Complete(r)
}    

func NameIndexer(o client.Object) []string {
    m := o.(*cronjobv1alpha1.CronJob)
    return []string{m.ObjectMeta.Name}
}

func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    cronjobList := cronjobv1alpha1.CronJobList{}
    err = r.List(ctx, &amp;cronjobList, client.MatchingFields{&quot;metadata.name&quot;: &quot;test&quot;})
    if err != nil {
        return ctrl.Result{}, err
    }
}
</code></pre>
