diff --git a/addons/controllers/cpi/vspherecpiconfig_controller.go b/addons/controllers/cpi/vspherecpiconfig_controller.go index 46ba073f11..03c8bd3191 100644 --- a/addons/controllers/cpi/vspherecpiconfig_controller.go +++ b/addons/controllers/cpi/vspherecpiconfig_controller.go @@ -24,6 +24,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/source" addonconfig "github.com/vmware-tanzu/tanzu-framework/addons/pkg/config" "github.com/vmware-tanzu/tanzu-framework/addons/pkg/constants" @@ -79,18 +81,18 @@ var vsphereCPIProviderServiceAccountAggregatedClusterRole = &rbacv1.ClusterRole{ // Reconcile the VSphereCPIConfig CRD func (r *VSphereCPIConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - r.Log = r.Log.WithValues("VSphereCPIConfig", req.NamespacedName) + log := r.Log.WithValues("VSphereCPIConfig", req.NamespacedName) - r.Log.Info("Start reconciliation for VSphereCPIConfig") + log.Info("Start reconciliation for VSphereCPIConfig") // fetch VSphereCPIConfig resource cpiConfig := &cpiv1alpha1.VSphereCPIConfig{} if err := r.Client.Get(ctx, req.NamespacedName, cpiConfig); err != nil { if apierrors.IsNotFound(err) { - r.Log.Info("VSphereCPIConfig resource not found") + log.Info("VSphereCPIConfig resource not found") return ctrl.Result{}, nil } - r.Log.Error(err, "Unable to fetch VSphereCPIConfig resource") + log.Error(err, "Unable to fetch VSphereCPIConfig resource") return ctrl.Result{}, err } @@ -102,11 +104,11 @@ func (r *VSphereCPIConfigReconciler) Reconcile(ctx context.Context, req ctrl.Req return ctrl.Result{}, err // no need to requeue if cluster is not found } if cpiConfig.Spec.VSphereCPI.Mode == nil { - r.Log.Info("VSphere CPI mode is not provided.") + log.Info("VSphere CPI mode is not provided.") return ctrl.Result{}, nil // no need to requeue if CPI mode is not provided } if res, err := r.reconcileVSphereCPIConfig(ctx, cpiConfig, cluster); err != nil { - r.Log.Error(err, "Failed to reconcile VSphereCPIConfig") + log.Error(err, "Failed to reconcile VSphereCPIConfig") return res, err } return ctrl.Result{}, nil @@ -244,5 +246,9 @@ func (r *VSphereCPIConfigReconciler) SetupWithManager(_ context.Context, mgr ctr For(&cpiv1alpha1.VSphereCPIConfig{}). WithOptions(options). WithEventFilter(predicates.ConfigOfKindWithoutAnnotation(constants.TKGAnnotationTemplateConfig, constants.VSphereCPIConfigKind, r.Config.SystemNamespace, r.Log)). + Watches( + &source.Kind{Type: &capvvmwarev1beta1.VSphereCluster{}}, + handler.EnqueueRequestsFromMapFunc(r.VSphereClusterToVSphereCPIConfig), + ). Complete(r) } diff --git a/addons/controllers/cpi/vspherecpiconfig_utils.go b/addons/controllers/cpi/vspherecpiconfig_utils.go index 0b0de093ae..7e1548ae00 100644 --- a/addons/controllers/cpi/vspherecpiconfig_utils.go +++ b/addons/controllers/cpi/vspherecpiconfig_utils.go @@ -20,6 +20,9 @@ import ( capvv1beta1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1" capvvmwarev1beta1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/vmware/v1beta1" clusterapiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" + clusterapiutil "sigs.k8s.io/cluster-api/util" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/vmware-tanzu/tanzu-framework/addons/pkg/constants" pkgtypes "github.com/vmware-tanzu/tanzu-framework/addons/pkg/types" @@ -27,6 +30,52 @@ import ( cpiv1alpha1 "github.com/vmware-tanzu/tanzu-framework/apis/addonconfigs/cpi/v1alpha1" ) +// VSphereClusterToVSphereCPIConfig returns a list of Requests with VSphereCPIConfig ObjectKey based on Cluster events +func (r *VSphereCPIConfigReconciler) VSphereClusterToVSphereCPIConfig(o client.Object) []ctrl.Request { + cluster, ok := o.(*capvvmwarev1beta1.VSphereCluster) + if !ok { + r.Log.Error(errors.New("invalid type"), + "Expected to receive Cluster resource", + "actualType", fmt.Sprintf("%T", o)) + return nil + } + + r.Log.V(4).Info("Mapping VSphereCluster to VSphereCPIConfig") + + cs := &cpiv1alpha1.VSphereCPIConfigList{} + _ = r.List(context.Background(), cs) + + requests := []ctrl.Request{} + for i := 0; i < len(cs.Items); i++ { + config := &cs.Items[i] + if config.Namespace == cluster.Namespace { + + // avoid enqueuing reconcile requests for template vSphereCPIConfig CRs in event handler of Cluster CR + if _, ok := config.Annotations[constants.TKGAnnotationTemplateConfig]; ok && config.Namespace == r.Config.SystemNamespace { + continue + } + + // corresponding vsphereCPIConfig should have following ownerRef + ownerReference := metav1.OwnerReference{ + APIVersion: clusterapiv1beta1.GroupVersion.String(), + Kind: cluster.Kind, + Name: cluster.Name, + UID: cluster.UID, + } + if clusterapiutil.HasOwnerRef(config.OwnerReferences, ownerReference) || config.Name == fmt.Sprintf("%s-%s-package", cluster.Name, constants.CPIAddonName) { + r.Log.V(4).Info("Adding VSphereCPIConfig for reconciliation", + constants.NamespaceLogKey, config.Namespace, constants.NameLogKey, config.Name) + + requests = append(requests, ctrl.Request{ + NamespacedName: clusterapiutil.ObjectKey(config), + }) + } + } + } + + return requests +} + // mapCPIConfigToDataValuesNonParavirtual generates CPI data values for non-paravirtual modes func (r *VSphereCPIConfigReconciler) mapCPIConfigToDataValuesNonParavirtual( // nolint ctx context.Context, @@ -367,8 +416,8 @@ func (r *VSphereCPIConfigReconciler) getOwnerCluster(ctx context.Context, cpiCon } if err := r.Client.Get(ctx, types.NamespacedName{Namespace: cpiConfig.Namespace, Name: clusterName}, cluster); err != nil { if apierrors.IsNotFound(err) { - r.Log.Info(fmt.Sprintf("Cluster resource '%s/%s' not found", cpiConfig.Namespace, clusterName)) - return nil, nil + r.Log.Error(err, fmt.Sprintf("Cluster resource '%s/%s' not found", cpiConfig.Namespace, clusterName)) + return nil, err } r.Log.Error(err, fmt.Sprintf("Unable to fetch cluster '%s/%s'", cpiConfig.Namespace, clusterName)) return nil, err