github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/groups/actions.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package groups 16 17 import ( 18 "context" 19 "fmt" 20 "time" 21 22 "github.com/cilium/cilium/pkg/controller" 23 "github.com/cilium/cilium/pkg/k8s" 24 cilium_v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 25 "github.com/cilium/cilium/pkg/logging/logfields" 26 "github.com/cilium/cilium/pkg/metrics" 27 28 "github.com/sirupsen/logrus" 29 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 ) 31 32 const ( 33 // maxNumberOfAttempts Number of times that try to retrieve a information from a cloud provider. 34 maxNumberOfAttempts = 5 35 // SleepDuration time that sleep in case that can't retrieve information from a cloud provider. 36 sleepDuration = 5 * time.Second 37 ) 38 39 var ( 40 controllerManager = controller.NewManager() 41 ) 42 43 // AddDerivativeCNPIfNeeded will create a new CNP if the given CNP has any rule 44 // that need to create a new derivative policy. 45 // It returns a boolean, true in case that all actions are correct, false if 46 // something fails 47 func AddDerivativeCNPIfNeeded(cnp *cilium_v2.CiliumNetworkPolicy) bool { 48 if !cnp.RequiresDerivative() { 49 log.WithFields(logrus.Fields{ 50 logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name, 51 logfields.K8sNamespace: cnp.ObjectMeta.Namespace, 52 }).Debug("CNP does not have derivative policies, skipped") 53 return true 54 } 55 controllerManager.UpdateController(fmt.Sprintf("add-derivative-cnp-%s", cnp.ObjectMeta.Name), 56 controller.ControllerParams{ 57 DoFunc: func(ctx context.Context) error { 58 return addDerivativeCNP(cnp) 59 }, 60 }) 61 return true 62 } 63 64 // UpdateDerivativeCNPIfNeeded updates or creates a CNP if the given CNP has 65 // any rule that needs to create a new derivative policy(eg: ToGroups). In case 66 // that the new CNP does not have any derivative policy and the old one had 67 // one, it will delete the old policy. 68 func UpdateDerivativeCNPIfNeeded(newCNP *cilium_v2.CiliumNetworkPolicy, oldCNP *cilium_v2.CiliumNetworkPolicy) bool { 69 if !newCNP.RequiresDerivative() && oldCNP.RequiresDerivative() { 70 log.WithFields(logrus.Fields{ 71 logfields.CiliumNetworkPolicyName: newCNP.ObjectMeta.Name, 72 logfields.K8sNamespace: newCNP.ObjectMeta.Namespace, 73 }).Info("New CNP does not have derivative policy, but old had. Deleted old policies") 74 75 controllerManager.UpdateController(fmt.Sprintf("delete-derivatve-cnp-%s", oldCNP.ObjectMeta.Name), 76 controller.ControllerParams{ 77 DoFunc: func(ctx context.Context) error { 78 return DeleteDerivativeCNP(oldCNP) 79 }, 80 }) 81 return false 82 } 83 84 if !newCNP.RequiresDerivative() { 85 return false 86 } 87 88 controllerManager.UpdateController(fmt.Sprintf("CNP-Derivative-update-%s", newCNP.ObjectMeta.Name), 89 controller.ControllerParams{ 90 DoFunc: func(ctx context.Context) error { 91 return addDerivativeCNP(newCNP) 92 }, 93 }) 94 return true 95 } 96 97 // DeleteDerivativeFromCache deletes the given CNP from the groupsCNPCache to 98 // no continue pooling new data. 99 func DeleteDerivativeFromCache(cnp *cilium_v2.CiliumNetworkPolicy) { 100 groupsCNPCache.DeleteCNP(cnp) 101 } 102 103 // DeleteDerivativeCNP if the given policy has a derivative constraint,the 104 // given CNP will be deleted from store and the cache. 105 func DeleteDerivativeCNP(cnp *cilium_v2.CiliumNetworkPolicy) error { 106 107 scopedLog := log.WithFields(logrus.Fields{ 108 logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name, 109 logfields.K8sNamespace: cnp.ObjectMeta.Namespace, 110 }) 111 112 if !cnp.RequiresDerivative() { 113 scopedLog.Debug("CNP does not have derivative policies, skipped") 114 return nil 115 } 116 117 err := k8s.CiliumClient().CiliumV2().CiliumNetworkPolicies(cnp.ObjectMeta.Namespace).DeleteCollection( 118 &v1.DeleteOptions{}, 119 v1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", parentCNP, cnp.ObjectMeta.UID)}) 120 121 if err != nil { 122 return err 123 } 124 125 DeleteDerivativeFromCache(cnp) 126 return nil 127 } 128 129 func addDerivativeCNP(cnp *cilium_v2.CiliumNetworkPolicy) error { 130 131 scopedLog := log.WithFields(logrus.Fields{ 132 logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name, 133 logfields.K8sNamespace: cnp.ObjectMeta.Namespace, 134 }) 135 136 var derivativeCNP *cilium_v2.CiliumNetworkPolicy 137 var derivativeErr error 138 139 // The maxNumberOfAttempts is to not hit the limits of cloud providers API. 140 // Also, the derivativeErr is never returned, if not the controller will 141 // hit this function and the cloud providers limit will be raised. This 142 // will cause a disaster, due all other policies will hit the limit as 143 // well. 144 // If the createDerivativeCNP() fails, a new all block rule will be inserted and 145 // the derivative status in the parent policy will be updated with the 146 // error. 147 for numAttempts := 0; numAttempts <= maxNumberOfAttempts; numAttempts++ { 148 derivativeCNP, derivativeErr = createDerivativeCNP(cnp) 149 if derivativeErr == nil { 150 break 151 } 152 metrics.PolicyImportErrors.Inc() 153 scopedLog.WithError(derivativeErr).Error("Cannot create derivative rule. Installing deny-all rule.") 154 statusErr := updateDerivativeStatus(cnp, derivativeCNP.ObjectMeta.Name, derivativeErr) 155 if statusErr != nil { 156 scopedLog.WithError(statusErr).Error("Cannot update CNP status for derivative policy") 157 } 158 time.Sleep(sleepDuration) 159 } 160 groupsCNPCache.UpdateCNP(cnp) 161 _, err := updateOrCreateCNP(derivativeCNP) 162 if err != nil { 163 statusErr := updateDerivativeStatus(cnp, derivativeCNP.ObjectMeta.Name, err) 164 if statusErr != nil { 165 metrics.PolicyImportErrors.Inc() 166 scopedLog.WithError(err).Error("Cannot update CNP status for derivative policy") 167 } 168 return statusErr 169 } 170 171 err = updateDerivativeStatus(cnp, derivativeCNP.ObjectMeta.Name, nil) 172 if err != nil { 173 scopedLog.WithError(err).Error("Cannot update CNP status for derivative policy") 174 } 175 return err 176 }