open-cluster-management.io/governance-policy-propagator@v0.13.0/controllers/propagator/rootpolicy_controller.go (about) 1 // Copyright (c) 2021 Red Hat, Inc. 2 // Copyright Contributors to the Open Cluster Management project 3 4 package propagator 5 6 import ( 7 "context" 8 "sync" 9 10 k8serrors "k8s.io/apimachinery/pkg/api/errors" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 ctrl "sigs.k8s.io/controller-runtime" 13 "sigs.k8s.io/controller-runtime/pkg/client" 14 "sigs.k8s.io/controller-runtime/pkg/event" 15 "sigs.k8s.io/controller-runtime/pkg/reconcile" 16 17 policiesv1 "open-cluster-management.io/governance-policy-propagator/api/v1" 18 "open-cluster-management.io/governance-policy-propagator/controllers/common" 19 ) 20 21 const ControllerName string = "policy-propagator" 22 23 var log = ctrl.Log.WithName(ControllerName) 24 25 type RootPolicyReconciler struct { 26 Propagator 27 } 28 29 // Reconcile handles root policies, sending events to the replicated policy reconciler to ensure 30 // that the desired policies are on the correct clusters. It also populates the status of the root 31 // policy with placement information. 32 func (r *RootPolicyReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) { 33 log := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) 34 35 log.V(3).Info("Acquiring the lock for the root policy") 36 37 lock, _ := r.RootPolicyLocks.LoadOrStore(request.NamespacedName, &sync.Mutex{}) 38 39 lock.(*sync.Mutex).Lock() 40 defer lock.(*sync.Mutex).Unlock() 41 42 log.Info("Reconciling the policy") 43 44 // Fetch the Policy instance 45 instance := &policiesv1.Policy{} 46 47 err := r.Get(ctx, request.NamespacedName, instance) 48 if err != nil { 49 if k8serrors.IsNotFound(err) { 50 count, err := r.updateExistingReplicas(ctx, request.Namespace+"."+request.Name) 51 if err != nil { 52 log.Error(err, "Failed to send update events to replicated policies, requeueing") 53 54 return reconcile.Result{}, err 55 } 56 57 log.Info("Replicated policies sent for deletion", "count", count) 58 59 return reconcile.Result{}, nil 60 } 61 62 log.Error(err, "Failed to get the policy") 63 64 // Error reading the object - requeue the request. 65 return reconcile.Result{}, err 66 } 67 68 inClusterNs, err := common.IsInClusterNamespace(ctx, r.Client, instance.Namespace) 69 if err != nil { 70 log.Error(err, "Failed to determine if the policy is in a managed cluster namespace. Requeueing the request.") 71 72 return reconcile.Result{}, err 73 } 74 75 if !inClusterNs { 76 err := r.handleRootPolicy(ctx, instance) 77 if err != nil { 78 log.Error(err, "Failure during root policy handling") 79 80 propagationFailureMetric.WithLabelValues(instance.GetName(), instance.GetNamespace()).Inc() 81 } 82 83 log.Info("Reconciliation complete") 84 85 return reconcile.Result{}, err 86 } 87 88 log = log.WithValues("name", instance.GetName(), "namespace", instance.GetNamespace()) 89 90 log.Info("The policy was found in the cluster namespace but doesn't belong to any root policy, deleting it") 91 92 err = r.Delete(ctx, instance) 93 if err != nil && !k8serrors.IsNotFound(err) { 94 log.Error(err, "Failed to delete the policy") 95 96 return reconcile.Result{}, err 97 } 98 99 return reconcile.Result{}, nil 100 } 101 102 // updateExistingReplicas lists all existing replicated policies for this root policy, and sends 103 // events for each of them to the replicated policy reconciler. This will trigger updates on those 104 // replicated policies, for example when the root policy spec changes, or when the replicated 105 // policies might need to be deleted. 106 func (r *RootPolicyReconciler) updateExistingReplicas(ctx context.Context, rootPolicyFullName string) (int, error) { 107 // Get all the replicated policies for this root policy 108 policyList := &policiesv1.PolicyList{} 109 opts := &client.ListOptions{} 110 111 matcher := client.MatchingLabels{common.RootPolicyLabel: rootPolicyFullName} 112 matcher.ApplyToList(opts) 113 114 err := r.List(ctx, policyList, opts) 115 if err != nil && !k8serrors.IsNotFound(err) { 116 return 0, err 117 } 118 119 for _, replicated := range policyList.Items { 120 simpleObj := &common.GuttedObject{ 121 TypeMeta: metav1.TypeMeta{ 122 Kind: replicated.Kind, 123 APIVersion: replicated.APIVersion, 124 }, 125 ObjectMeta: metav1.ObjectMeta{ 126 Name: replicated.Name, 127 Namespace: replicated.Namespace, 128 }, 129 } 130 131 r.ReplicatedPolicyUpdates <- event.GenericEvent{Object: simpleObj} 132 } 133 134 return len(policyList.Items), nil 135 }