7878 Help : "The number of IP addresses assigned to pods" ,
7979 },
8080 )
81+ forceRemovedENIs = prometheus .NewCounter (
82+ prometheus.CounterOpts {
83+ Name : "awscni_force_removed_enis" ,
84+ Help : "The number of ENIs force removed while they had assigned pods" ,
85+ },
86+ )
87+ forceRemovedIPs = prometheus .NewCounter (
88+ prometheus.CounterOpts {
89+ Name : "awscni_force_removed_ips" ,
90+ Help : "The number of IPs force removed while they had assigned pods" ,
91+ },
92+ )
8193 prometheusRegistered = false
8294)
8395
@@ -146,6 +158,8 @@ func prometheusRegister() {
146158 prometheus .MustRegister (enis )
147159 prometheus .MustRegister (totalIPs )
148160 prometheus .MustRegister (assignedIPs )
161+ prometheus .MustRegister (forceRemovedENIs )
162+ prometheus .MustRegister (forceRemovedIPs )
149163 prometheusRegistered = true
150164 }
151165}
@@ -209,7 +223,7 @@ func (ds *DataStore) AddIPv4AddressToStore(eniID string, ipv4 string) error {
209223}
210224
211225// DelIPv4AddressFromStore delete an IP of ENI from datastore
212- func (ds * DataStore ) DelIPv4AddressFromStore (eniID string , ipv4 string ) error {
226+ func (ds * DataStore ) DelIPv4AddressFromStore (eniID string , ipv4 string , force bool ) error {
213227 ds .lock .Lock ()
214228 defer ds .lock .Unlock ()
215229 log .Debugf ("Deleting ENI(%s)'s IPv4 address %s from datastore" , eniID , ipv4 )
@@ -226,7 +240,18 @@ func (ds *DataStore) DelIPv4AddressFromStore(eniID string, ipv4 string) error {
226240 }
227241
228242 if ipAddr .Assigned {
229- return errors .New (IPInUseError )
243+ if ! force {
244+ return errors .New (IPInUseError )
245+ }
246+ log .Warnf ("Force deleting assigned ip %s on eni %s" , ipv4 , eniID )
247+ forceRemovedIPs .Inc ()
248+ decrementAssignedCount (ds , curENI , ipAddr )
249+ for key , info := range ds .podsIP {
250+ if info .IP == ipv4 {
251+ delete (ds .podsIP , key )
252+ break
253+ }
254+ }
230255 }
231256
232257 ds .total --
@@ -307,6 +332,17 @@ func incrementAssignedCount(ds *DataStore, eni *ENIIPPool, addr *AddressInfo) {
307332 assignedIPs .Set (float64 (ds .assigned ))
308333}
309334
335+ func decrementAssignedCount (ds * DataStore , eni * ENIIPPool , addr * AddressInfo ) {
336+ ds .assigned --
337+ eni .AssignedIPv4Addresses --
338+ addr .Assigned = false
339+ curTime := time .Now ()
340+ eni .lastUnassignedTime = curTime
341+ addr .UnassignedTime = curTime
342+ // Prometheus gauge
343+ assignedIPs .Set (float64 (ds .assigned ))
344+ }
345+
310346// GetStats returns total number of IP addresses and number of assigned IP addresses
311347func (ds * DataStore ) GetStats () (int , int ) {
312348 return ds .total , ds .assigned
@@ -431,7 +467,7 @@ func (ds *DataStore) RemoveUnusedENIFromStore(warmIPTarget int, minimumIPTarget
431467}
432468
433469// RemoveENIFromDataStore removes an ENI from the datastore. It return nil on success or an error.
434- func (ds * DataStore ) RemoveENIFromDataStore (eni string ) error {
470+ func (ds * DataStore ) RemoveENIFromDataStore (eni string , force bool ) error {
435471 ds .lock .Lock ()
436472 defer ds .lock .Unlock ()
437473
@@ -440,9 +476,26 @@ func (ds *DataStore) RemoveENIFromDataStore(eni string) error {
440476 return errors .New (UnknownENIError )
441477 }
442478
443- // Only unused ENIs can be deleted
444- if eniIPPool .AssignedIPv4Addresses != 0 {
445- return errors .New (ENIInUseError )
479+ if eniIPPool .hasPods () {
480+ if ! force {
481+ return errors .New (ENIInUseError )
482+ }
483+ // This scenario can occur if the reconciliation process discovered this eni was detached
484+ // from the EC2 instance outside of the control of ipamd. If this happens, there's nothing
485+ // we can do other than force all pods to be unassigned from the IPs on this eni.
486+ log .Warnf ("Force removing eni %s with %d assigned pods" , eni , eniIPPool .AssignedIPv4Addresses )
487+ forceRemovedENIs .Inc ()
488+ forceRemovedIPs .Add (float64 (eniIPPool .AssignedIPv4Addresses ))
489+ for _ , addr := range eniIPPool .IPv4Addresses {
490+ if addr .Assigned {
491+ decrementAssignedCount (ds , eniIPPool , addr )
492+ }
493+ }
494+ for key , info := range ds .podsIP {
495+ if info .DeviceNumber == eniIPPool .DeviceNumber {
496+ delete (ds .podsIP , key )
497+ }
498+ }
446499 }
447500
448501 ds .total -= len (eniIPPool .IPv4Addresses )
@@ -478,13 +531,7 @@ func (ds *DataStore) UnassignPodIPv4Address(k8sPod *k8sapi.K8SPodInfo) (ip strin
478531 for _ , eni := range ds .eniIPPools {
479532 ip , ok := eni .IPv4Addresses [ipAddr .IP ]
480533 if ok && ip .Assigned {
481- ip .Assigned = false
482- ds .assigned --
483- assignedIPs .Set (float64 (ds .assigned ))
484- eni .AssignedIPv4Addresses --
485- curTime := time .Now ()
486- ip .UnassignedTime = curTime
487- eni .lastUnassignedTime = curTime
534+ decrementAssignedCount (ds , eni , ip )
488535 log .Infof ("UnassignPodIPv4Address: pod (Name: %s, NameSpace %s Sandbox %s)'s ipAddr %s, DeviceNumber%d" ,
489536 k8sPod .Name , k8sPod .Namespace , k8sPod .Sandbox , ip .Address , eni .DeviceNumber )
490537 delete (ds .podsIP , podKey )
0 commit comments