Skip to content

Commit 8449676

Browse files
authored
feature: don't let CNS ask for more IPS than node limit (#843)
* feature: CNS to honor MaxIPCount in CRD for scaling events
1 parent a4b844a commit 8449676

File tree

2 files changed

+263
-14
lines changed

2 files changed

+263
-14
lines changed

cns/ipampoolmonitor/ipampoolmonitor.go

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import (
1212
nnc "github.com/Azure/azure-container-networking/nodenetworkconfig/api/v1alpha"
1313
)
1414

15+
const (
16+
defaultMaxIPCount = int64(250)
17+
)
18+
1519
type CNSIPAMPoolMonitor struct {
1620
pendingRelease bool
1721

@@ -71,12 +75,21 @@ func (pm *CNSIPAMPoolMonitor) Reconcile() error {
7175
pendingReleaseIPCount := len(pm.httpService.GetPendingReleaseIPConfigs())
7276
availableIPConfigCount := len(pm.httpService.GetAvailableIPConfigs()) // TODO: add pending allocation count to real cns
7377
freeIPConfigCount := pm.cachedNNC.Spec.RequestedIPCount - int64(allocatedPodIPCount)
74-
msg := fmt.Sprintf("[ipam-pool-monitor] Pool Size: %v, Goal Size: %v, BatchSize: %v, MinFree: %v, MaxFree:%v, Allocated: %v, Available: %v, Pending Release: %v, Free: %v, Pending Program: %v",
75-
cnsPodIPConfigCount, pm.cachedNNC.Spec.RequestedIPCount, pm.scalarUnits.BatchSize, pm.MinimumFreeIps, pm.MaximumFreeIps, allocatedPodIPCount, availableIPConfigCount, pendingReleaseIPCount, freeIPConfigCount, pendingProgramCount)
78+
batchSize := pm.getBatchSize() //Use getters in case customer changes batchsize manually
79+
maxIPCount := pm.getMaxIPCount()
80+
81+
82+
msg := fmt.Sprintf("[ipam-pool-monitor] Pool Size: %v, Goal Size: %v, BatchSize: %v, MaxIPCount: %v, MinFree: %v, MaxFree:%v, Allocated: %v, Available: %v, Pending Release: %v, Free: %v, Pending Program: %v",
83+
cnsPodIPConfigCount, pm.cachedNNC.Spec.RequestedIPCount, batchSize, maxIPCount, pm.MinimumFreeIps, pm.MaximumFreeIps, allocatedPodIPCount, availableIPConfigCount, pendingReleaseIPCount, freeIPConfigCount, pendingProgramCount)
7684

7785
switch {
7886
// pod count is increasing
7987
case freeIPConfigCount < pm.MinimumFreeIps:
88+
if pm.cachedNNC.Spec.RequestedIPCount == maxIPCount {
89+
// If we're already at the maxIPCount, don't try to increase
90+
return nil
91+
}
92+
8093
logger.Printf("[ipam-pool-monitor] Increasing pool size...%s ", msg)
8194
return pm.increasePoolSize()
8295

@@ -111,7 +124,24 @@ func (pm *CNSIPAMPoolMonitor) increasePoolSize() error {
111124
return err
112125
}
113126

114-
tempNNCSpec.RequestedIPCount += pm.scalarUnits.BatchSize
127+
// Query the max IP count
128+
maxIPCount := pm.getMaxIPCount()
129+
previouslyRequestedIPCount := tempNNCSpec.RequestedIPCount
130+
batchSize := pm.getBatchSize()
131+
132+
tempNNCSpec.RequestedIPCount += batchSize
133+
if tempNNCSpec.RequestedIPCount > maxIPCount {
134+
// We don't want to ask for more ips than the max
135+
logger.Printf("[ipam-pool-monitor] Requested IP count (%v) is over max limit (%v), requesting max limit instead.", tempNNCSpec.RequestedIPCount, maxIPCount)
136+
tempNNCSpec.RequestedIPCount = maxIPCount
137+
}
138+
139+
// If the requested IP count is same as before, then don't do anything
140+
if tempNNCSpec.RequestedIPCount == previouslyRequestedIPCount {
141+
logger.Printf("[ipam-pool-monitor] Previously requested IP count %v is same as updated IP count %v, doing nothing", previouslyRequestedIPCount, tempNNCSpec.RequestedIPCount)
142+
return nil
143+
}
144+
115145
logger.Printf("[ipam-pool-monitor] Increasing pool size, Current Pool Size: %v, Updated Requested IP Count: %v, Pods with IP's:%v, ToBeDeleted Count: %v", len(pm.httpService.GetPodIPConfigState()), tempNNCSpec.RequestedIPCount, len(pm.httpService.GetAllocatedIPConfigs()), len(tempNNCSpec.IPsNotInUse))
116146

117147
err = pm.rc.UpdateCRDSpec(context.Background(), tempNNCSpec)
@@ -134,10 +164,35 @@ func (pm *CNSIPAMPoolMonitor) decreasePoolSize(existingPendingReleaseIPCount int
134164
var err error
135165
var newIpsMarkedAsPending bool
136166
var pendingIpAddresses map[string]cns.IPConfigurationStatus
167+
var updatedRequestedIPCount int64
168+
var decreaseIPCountBy int64
169+
170+
// Ensure the updated requested IP count is a multiple of the batch size
171+
previouslyRequestedIPCount := pm.cachedNNC.Spec.RequestedIPCount
172+
batchSize := pm.getBatchSize()
173+
modResult := previouslyRequestedIPCount % batchSize
174+
175+
logger.Printf("[ipam-pool-monitor] Previously RequestedIP Count %v", previouslyRequestedIPCount)
176+
logger.Printf("[ipam-pool-monitor] Batch size : %v", batchSize)
177+
logger.Printf("[ipam-pool-monitor] modResult of (previously requested IP count mod batch size) = %v", modResult)
178+
179+
if modResult != 0 {
180+
// Example: previouscount = 25, batchsize = 10, 25 - 10 = 15, NOT a multiple of batchsize (10)
181+
// Don't want that, so make requestedIPCount 20 (25 - (25 % 10)) so that it is a multiple of the batchsize (10)
182+
updatedRequestedIPCount = previouslyRequestedIPCount - modResult
183+
} else {
184+
// Example: previouscount = 30, batchsize = 10, 30 - 10 = 20 which is multiple of batchsize (10) so all good
185+
updatedRequestedIPCount = previouslyRequestedIPCount - batchSize
186+
}
187+
188+
decreaseIPCountBy = previouslyRequestedIPCount - updatedRequestedIPCount
189+
190+
logger.Printf("[ipam-pool-monitor] updatedRequestedIPCount %v", updatedRequestedIPCount)
191+
137192
if pm.updatingIpsNotInUseCount == 0 ||
138193
pm.updatingIpsNotInUseCount < existingPendingReleaseIPCount {
139-
logger.Printf("[ipam-pool-monitor] Marking IPs as PendingRelease, ipsToBeReleasedCount %d", int(pm.scalarUnits.BatchSize))
140-
pendingIpAddresses, err = pm.httpService.MarkIPAsPendingRelease(int(pm.scalarUnits.BatchSize))
194+
logger.Printf("[ipam-pool-monitor] Marking IPs as PendingRelease, ipsToBeReleasedCount %d", int(decreaseIPCountBy))
195+
pendingIpAddresses, err = pm.httpService.MarkIPAsPendingRelease(int(decreaseIPCountBy))
141196
if err != nil {
142197
return err
143198
}
@@ -237,8 +292,8 @@ func (pm *CNSIPAMPoolMonitor) Update(scalar nnc.Scaler, spec nnc.NodeNetworkConf
237292

238293
pm.scalarUnits = scalar
239294

240-
pm.MinimumFreeIps = int64(float64(pm.scalarUnits.BatchSize) * (float64(pm.scalarUnits.RequestThresholdPercent) / 100))
241-
pm.MaximumFreeIps = int64(float64(pm.scalarUnits.BatchSize) * (float64(pm.scalarUnits.ReleaseThresholdPercent) / 100))
295+
pm.MinimumFreeIps = int64(float64(pm.getBatchSize()) * (float64(pm.scalarUnits.RequestThresholdPercent) / 100))
296+
pm.MaximumFreeIps = int64(float64(pm.getBatchSize()) * (float64(pm.scalarUnits.ReleaseThresholdPercent) / 100))
242297

243298
pm.cachedNNC.Spec = spec
244299

@@ -248,6 +303,21 @@ func (pm *CNSIPAMPoolMonitor) Update(scalar nnc.Scaler, spec nnc.NodeNetworkConf
248303
return nil
249304
}
250305

306+
func (pm *CNSIPAMPoolMonitor) getMaxIPCount() int64 {
307+
if pm.scalarUnits.MaxIPCount == 0 {
308+
pm.scalarUnits.MaxIPCount = defaultMaxIPCount
309+
}
310+
return pm.scalarUnits.MaxIPCount
311+
}
312+
313+
func (pm *CNSIPAMPoolMonitor) getBatchSize() int64 {
314+
maxIPCount := pm.getMaxIPCount()
315+
if pm.scalarUnits.BatchSize > maxIPCount {
316+
pm.scalarUnits.BatchSize = maxIPCount
317+
}
318+
return pm.scalarUnits.BatchSize
319+
}
320+
251321
//this function sets the values for state in IPAMPoolMonitor Struct
252322
func (pm *CNSIPAMPoolMonitor) GetStateSnapshot() cns.IpamPoolMonitorStateSnapshot {
253323
pm.mu.Lock()

0 commit comments

Comments
 (0)