@@ -20,6 +20,7 @@ import (
2020var (
2121 ErrStoreEmpty = errors .New ("empty endpoint state store" )
2222 ErrParsePodIPFailed = errors .New ("failed to parse pod's ip" )
23+ ErrNoNCs = errors .New ("No NCs found in the CNS internal state" )
2324)
2425
2526// requestIPConfigHandlerHelper validates the request, assigns IPs, and returns a response
@@ -88,13 +89,13 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r
8889 return
8990 }
9091
91- // This method can only return 1 IP. If we have more than one NC then we expect to need to return one IP per NC
92- if len (service .state .ContainerStatus ) > 1 {
92+ // This method can only return EXACTLY 1 IP. If we have more than one NC then we expect to need to return one IP per NC
93+ if len (service .state .ContainerStatus ) != 1 {
9394 // we send a response back saying that this API won't be able to return the amount of IPs needed to fulfill the request
9495 reserveResp := & cns.IPConfigResponse {
9596 Response : cns.Response {
9697 ReturnCode : types .InvalidRequest ,
97- Message : fmt .Sprintf ("Called API that can only return 1 IP when expecting %d " , len (service .state .ContainerStatus )),
98+ Message : fmt .Sprintf ("Expected 1 NC when calling this API but found %d NCs " , len (service .state .ContainerStatus )),
9899 },
99100 }
100101 w .Header ().Set (cnsReturnCode , reserveResp .Response .ReturnCode .String ())
@@ -128,6 +129,21 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r
128129 return
129130 }
130131
132+ // Checks to make sure we return exactly 1 IP
133+ // If IPAM assigned more than 1 IP then we need to raise an error since this API can only return one IP and IPAM may have assigned more than one
134+ if len (ipConfigsResp .PodIPInfo ) != 1 {
135+ // we send a response back saying that this API won't be able to return the amount of IPs needed to fulfill the request
136+ reserveResp := & cns.IPConfigResponse {
137+ Response : cns.Response {
138+ ReturnCode : types .UnexpectedError ,
139+ Message : fmt .Sprintf ("request returned incorrect number of IPs. Expected 1 and returned %d" , len (ipConfigsResp .PodIPInfo )),
140+ },
141+ }
142+ w .Header ().Set (cnsReturnCode , reserveResp .Response .ReturnCode .String ())
143+ err = service .Listener .Encode (w , & reserveResp )
144+ logger .ResponseEx (service .Name + operationName , ipconfigRequest , reserveResp , reserveResp .Response .ReturnCode , err )
145+ return
146+ }
131147 // As this API is expected to return IPConfigResponse, generate it from the IPConfigsResponse returned above.
132148 reserveResp := & cns.IPConfigResponse {
133149 Response : ipConfigsResp .Response ,
@@ -273,12 +289,12 @@ func (service *HTTPRestService) releaseIPConfigHandler(w http.ResponseWriter, r
273289 return
274290 }
275291
276- // check to make sure there aren't multiple NCs
277- if len (service .state .ContainerStatus ) > 1 {
292+ // check to make sure there is only one NC
293+ if len (service .state .ContainerStatus ) != 1 {
278294 reserveResp := & cns.IPConfigResponse {
279295 Response : cns.Response {
280296 ReturnCode : types .InvalidRequest ,
281- Message : fmt .Sprintf ("Called API that can only return 1 IP when expecting %d " , len (service .state .ContainerStatus )),
297+ Message : fmt .Sprintf ("Expected 1 NC when calling this API but found %d NCs " , len (service .state .ContainerStatus )),
282298 },
283299 }
284300 w .Header ().Set (cnsReturnCode , reserveResp .Response .ReturnCode .String ())
@@ -661,7 +677,15 @@ func (service *HTTPRestService) GetExistingIPConfig(podInfo cns.PodInfo) ([]cns.
661677
662678// Assigns a pod with all IPs desired
663679func (service * HTTPRestService ) AssignDesiredIPConfigs (podInfo cns.PodInfo , desiredIPAddresses []string ) ([]cns.PodIpInfo , error ) {
680+ // Gets the number of NCs which will determine the number of IPs given to a pod
681+ numOfNCs := len (service .state .ContainerStatus )
682+ // checks to make sure we have NCs before trying to get IPs
683+ if numOfNCs == 0 {
684+ return nil , ErrNoNCs
685+ }
686+ // Sets the number of desired IPs equal to the number of desired IPs passed in
664687 numDesiredIPAddresses := len (desiredIPAddresses )
688+ // Creates a slice of PodIpInfo with the size as number of NCs to hold the result for assigned IP configs
665689 podIPInfo := make ([]cns.PodIpInfo , numDesiredIPAddresses )
666690 // creating a map for the loop to check to see if the IP in the pool is one of the desired IPs
667691 desiredIPMap := make (map [string ]struct {})
@@ -756,12 +780,16 @@ func (service *HTTPRestService) AssignDesiredIPConfigs(podInfo cns.PodInfo, desi
756780// Assigns an available IP from each NC on the NNC. If there is one NC then we expect to only have one IP return
757781// In the case of dualstack we would expect to have one IPv6 from one NC and one IPv4 from a second NC
758782func (service * HTTPRestService ) AssignAvailableIPConfigs (podInfo cns.PodInfo ) ([]cns.PodIpInfo , error ) {
783+ // Gets the number of NCs which will determine the number of IPs given to a pod
784+ numOfNCs := len (service .state .ContainerStatus )
785+ // if there are no NCs on the NNC there will be no IPs in the pool so return error
786+ if numOfNCs == 0 {
787+ return nil , ErrNoNCs
788+ }
759789 service .Lock ()
760790 defer service .Unlock ()
761- // Sets the number of IPs needed equal to the number of NCs so that we can get one IP per NC
762- numIPsNeeded := len (service .state .ContainerStatus )
763791 // Creates a slice of PodIpInfo with the size as number of NCs to hold the result for assigned IP configs
764- podIPInfo := make ([]cns.PodIpInfo , numIPsNeeded )
792+ podIPInfo := make ([]cns.PodIpInfo , numOfNCs )
765793 // This map is used to store whether or not we have found an available IP from an NC when looping through the pool
766794 ipsToAssign := make (map [string ]cns.IPConfigurationStatus )
767795
@@ -777,13 +805,13 @@ func (service *HTTPRestService) AssignAvailableIPConfigs(podInfo cns.PodInfo) ([
777805 }
778806 ipsToAssign [ipState .NCID ] = ipState
779807 // Once one IP per container is found break out of the loop and stop searching
780- if len (ipsToAssign ) == numIPsNeeded {
808+ if len (ipsToAssign ) == numOfNCs {
781809 break
782810 }
783811 }
784812
785813 // Checks to make sure we found one IP for each NC
786- if len (ipsToAssign ) != numIPsNeeded {
814+ if len (ipsToAssign ) != numOfNCs {
787815 //nolint:goerr113 // return error
788816 return podIPInfo , fmt .Errorf ("not enough IPs available, waiting on Azure CNS to allocate more" )
789817 }
0 commit comments