sigs.k8s.io/cluster-api@v1.7.1/exp/util/util.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package util implements utility functions.
    18  package util
    19  
    20  import (
    21  	"context"
    22  
    23  	"github.com/go-logr/logr"
    24  	"github.com/pkg/errors"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	"k8s.io/klog/v2"
    28  	"sigs.k8s.io/controller-runtime/pkg/client"
    29  	"sigs.k8s.io/controller-runtime/pkg/handler"
    30  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    31  
    32  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    33  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    34  	"sigs.k8s.io/cluster-api/util/labels/format"
    35  )
    36  
    37  // GetOwnerMachinePool returns the MachinePool objects owning the current resource.
    38  func GetOwnerMachinePool(ctx context.Context, c client.Client, obj metav1.ObjectMeta) (*expv1.MachinePool, error) {
    39  	for _, ref := range obj.GetOwnerReferences() {
    40  		if ref.Kind != "MachinePool" {
    41  			continue
    42  		}
    43  		gv, err := schema.ParseGroupVersion(ref.APIVersion)
    44  		if err != nil {
    45  			return nil, errors.WithStack(err)
    46  		}
    47  		if gv.Group == expv1.GroupVersion.Group {
    48  			return GetMachinePoolByName(ctx, c, obj.Namespace, ref.Name)
    49  		}
    50  	}
    51  	return nil, nil
    52  }
    53  
    54  // GetMachinePoolByName finds and returns a MachinePool object using the specified params.
    55  func GetMachinePoolByName(ctx context.Context, c client.Client, namespace, name string) (*expv1.MachinePool, error) {
    56  	m := &expv1.MachinePool{}
    57  	key := client.ObjectKey{Name: name, Namespace: namespace}
    58  	if err := c.Get(ctx, key, m); err != nil {
    59  		return nil, err
    60  	}
    61  	return m, nil
    62  }
    63  
    64  // GetMachinePoolByLabels finds and returns a MachinePool object using the value of clusterv1.MachinePoolNameLabel.
    65  // This differs from GetMachinePoolByName as the label value can be a hash.
    66  func GetMachinePoolByLabels(ctx context.Context, c client.Client, namespace string, labels map[string]string) (*expv1.MachinePool, error) {
    67  	selector := map[string]string{}
    68  	if clusterName, ok := labels[clusterv1.ClusterNameLabel]; ok {
    69  		selector = map[string]string{clusterv1.ClusterNameLabel: clusterName}
    70  	}
    71  
    72  	if poolNameHash, ok := labels[clusterv1.MachinePoolNameLabel]; ok {
    73  		machinePoolList := &expv1.MachinePoolList{}
    74  		if err := c.List(ctx, machinePoolList, client.InNamespace(namespace), client.MatchingLabels(selector)); err != nil {
    75  			return nil, errors.Wrapf(err, "failed to list MachinePools using labels %v", selector)
    76  		}
    77  
    78  		for _, mp := range machinePoolList.Items {
    79  			if format.MustFormatValue(mp.Name) == poolNameHash {
    80  				return &mp, nil
    81  			}
    82  		}
    83  	} else {
    84  		return nil, errors.Errorf("labels missing required key `%s`", clusterv1.MachinePoolNameLabel)
    85  	}
    86  
    87  	return nil, nil
    88  }
    89  
    90  // MachinePoolToInfrastructureMapFunc returns a handler.MapFunc that watches for
    91  // MachinePool events and returns reconciliation requests for an infrastructure provider object.
    92  func MachinePoolToInfrastructureMapFunc(gvk schema.GroupVersionKind, log logr.Logger) handler.MapFunc {
    93  	log = log.WithValues("machine-pool-to-infra-map-func", gvk.String())
    94  	return func(_ context.Context, o client.Object) []reconcile.Request {
    95  		m, ok := o.(*expv1.MachinePool)
    96  		if !ok {
    97  			log.V(4).Info("Not a machine pool", "Object", klog.KObj(o))
    98  			return nil
    99  		}
   100  		log := log.WithValues("MachinePool", klog.KObj(o))
   101  
   102  		gk := gvk.GroupKind()
   103  		ref := m.Spec.Template.Spec.InfrastructureRef
   104  		// Return early if the GroupKind doesn't match what we expect.
   105  		infraGK := ref.GroupVersionKind().GroupKind()
   106  		if gk != infraGK {
   107  			log.V(4).Info("Infra kind doesn't match filter group kind", "infrastructureGroupKind", infraGK.String())
   108  			return nil
   109  		}
   110  
   111  		log.V(4).Info("Projecting object")
   112  		return []reconcile.Request{
   113  			{
   114  				NamespacedName: client.ObjectKey{
   115  					Namespace: m.Namespace,
   116  					Name:      ref.Name,
   117  				},
   118  			},
   119  		}
   120  	}
   121  }