in cns/restserver/ipam.go [888:987]
func (service *HTTPRestService) AssignDesiredIPConfigs(podInfo cns.PodInfo, desiredIPAddresses []string) ([]cns.PodIpInfo, error) {
service.Lock()
defer service.Unlock()
// Gets the number of NCs which will determine the number of IPs given to a pod
numOfNCs := len(service.state.ContainerStatus)
// checks to make sure we have NCs before trying to get IPs
if numOfNCs == 0 {
return nil, ErrNoNCs
}
// Sets the number of desired IPs equal to the number of desired IPs passed in
numDesiredIPAddresses := len(desiredIPAddresses)
// Creates a slice of PodIpInfo with the size as number of NCs to hold the result for assigned IP configs
podIPInfo := make([]cns.PodIpInfo, numDesiredIPAddresses)
// creating a map for the loop to check to see if the IP in the pool is one of the desired IPs
desiredIPMap := make(map[string]struct{})
// slice to keep track of IP configs to assign
ipConfigsToAssign := make([]cns.IPConfigurationStatus, 0)
for _, desiredIP := range desiredIPAddresses {
desiredIPMap[desiredIP] = struct{}{}
}
numIPConfigsAssigned := 0
for _, ipConfig := range service.PodIPConfigState { //nolint:gocritic // ignore copy
_, found := desiredIPMap[ipConfig.IPAddress]
// keep searching until the all the desired IPs are found
if !found {
continue
}
switch ipConfig.GetState() { //nolint:exhaustive // ignoring PendingRelease case intentionally
case types.Assigned:
// This IP has already been assigned, if it is assigned to same pod add the IP to podIPInfo
if ipConfig.PodInfo.Key() == podInfo.Key() {
logger.Printf("[AssignDesiredIPConfigs]: IP Config [%+v] is already assigned to this Pod [%+v]", ipConfig, podInfo)
if err := service.populateIPConfigInfoUntransacted(ipConfig, &podIPInfo[numIPConfigsAssigned]); err != nil {
//nolint:goerr113 // return error
return []cns.PodIpInfo{}, fmt.Errorf("[AssignDesiredIPConfigs] Failed to assign IP %+v requested for pod %+v since the IP is already assigned to %+v", ipConfig, podInfo, ipConfig.PodInfo)
}
numIPConfigsAssigned++
} else {
//nolint:goerr113 // return error
return []cns.PodIpInfo{}, fmt.Errorf("[AssignDesiredIPConfigs] Desired IP is already assigned %+v, requested for pod %+v", ipConfig, podInfo)
}
case types.Available, types.PendingProgramming:
// This race can happen during restart, where CNS state is lost and thus we have lost the NC programmed version
// As part of reconcile, we mark IPs as Assigned which are already assigned to Pods (listed from APIServer)
ipConfigsToAssign = append(ipConfigsToAssign, ipConfig)
default:
logger.Errorf("[AssignDesiredIPConfigs] Desired IP is not available %+v", ipConfig)
//nolint:goerr113 // return error
return podIPInfo, fmt.Errorf("IP not available")
}
// checks if found all of the desired IPs either as an available IP or already assigned to the pod
if len(ipConfigsToAssign)+numIPConfigsAssigned == numDesiredIPAddresses {
break
}
}
// if we did not find all of the desired IPs return an error
if len(ipConfigsToAssign)+numIPConfigsAssigned != numDesiredIPAddresses {
//nolint:goerr113 // return error
return podIPInfo, fmt.Errorf("not enough desired IPs found in pool")
}
failedToAssignIP := false
// assigns all IPs that were found as available to the pod
for i := range ipConfigsToAssign {
if err := service.assignIPConfig(ipConfigsToAssign[i], podInfo); err != nil {
logger.Errorf(err.Error())
failedToAssignIP = true
break
}
if err := service.populateIPConfigInfoUntransacted(ipConfigsToAssign[i], &podIPInfo[numIPConfigsAssigned]); err != nil {
logger.Errorf(err.Error())
failedToAssignIP = true
break
}
// adds to the newly assigned IP to the counter
numIPConfigsAssigned++
}
// if we were able to get at least one IP but not all of the desired IPs
if failedToAssignIP {
logger.Printf("[AssignDesiredIPConfigs] Failed to retrieve all desired IPs. Releasing all IPs that were found")
for i := range ipConfigsToAssign {
_, err := service.unassignIPConfig(ipConfigsToAssign[i], podInfo)
if err != nil {
logger.Errorf("[AssignDesiredIPConfigs] failed to mark IPConfig [%+v] back to Available. err: %v", ipConfigsToAssign[i], err)
}
}
//nolint:goerr113 // return error
return podIPInfo, fmt.Errorf("not all requested ips %v were found/available in the pool", desiredIPAddresses)
}
logger.Printf("[AssignDesiredIPConfigs] Successfully assigned all desired IPs for pod %+v", podInfo)
return podIPInfo, nil
}