@@ -25,6 +25,11 @@ import (
2525 "github.com/pkg/errors"
2626)
2727
28+ const (
29+ // Known API names we care about
30+ nmAgentSwiftV2API = "SwiftV2DhcpRehydrationFromGoalState"
31+ )
32+
2833// This file contains the internal functions called by either HTTP APIs (api.go) or
2934// internal APIs (definde in internalapi.go).
3035// This will be used internally (say by RequestController in case of AKS)
@@ -167,6 +172,7 @@ func (service *HTTPRestService) SyncHostNCVersion(ctx context.Context, channelMo
167172 service .Lock ()
168173 defer service .Unlock ()
169174 start := time .Now ()
175+
170176 programmedNCCount , err := service .syncHostNCVersion (ctx , channelMode )
171177 // even if we get an error, we want to write the CNI conflist if we have any NC programmed to any version
172178 if programmedNCCount > 0 {
@@ -202,6 +208,7 @@ func (service *HTTPRestService) syncHostNCVersion(ctx context.Context, channelMo
202208 logger .Errorf ("Received err when change nc version %s in containerstatus to int, err msg %v" , service .state .ContainerStatus [idx ].CreateNetworkContainerRequest .Version , err )
203209 continue
204210 }
211+ logger .Printf ("NC %s: local NC version %d, DNC NC version %d" , service .state .ContainerStatus [idx ].ID , localNCVersion , dncNCVersion )
205212 // host NC version is the NC version from NMAgent, if it's smaller than NC version from DNC, then append it to indicate it needs update.
206213 if localNCVersion < dncNCVersion {
207214 outdatedNCs [service .state .ContainerStatus [idx ].ID ] = struct {}{}
@@ -216,23 +223,43 @@ func (service *HTTPRestService) syncHostNCVersion(ctx context.Context, channelMo
216223 if len (outdatedNCs ) == 0 {
217224 return len (programmedNCs ), nil
218225 }
226+ logger .Printf ("outdatedNCs: %v" , outdatedNCs )
219227 ncVersionListResp , err := service .nma .GetNCVersionList (ctx )
220228 if err != nil {
221229 return len (programmedNCs ), errors .Wrap (err , "failed to get nc version list from nmagent" )
222230 }
223231
232+ // Get IMDS NC versions for delegated NIC scenarios
233+ imdsNCVersions , err := service .GetIMDSNCVersions (ctx )
234+ if err != nil {
235+ logger .Printf ("Failed to get NC versions from IMDS: %v" , err )
236+ // If any of the NMA API check calls, imds calls fails assume that nma build doesn't have the latest changes and create empty map
237+ imdsNCVersions = make (map [string ]string )
238+ }
239+
224240 nmaNCs := map [string ]string {}
225241 for _ , nc := range ncVersionListResp .Containers {
226242 nmaNCs [strings .ToLower (nc .NetworkContainerID )] = nc .Version
227243 }
228- hasNC .Set (float64 (len (nmaNCs )))
244+
245+ // Consolidate both maps - NMA takes precedence, IMDS as fallback
246+ consolidatedNCs := make (map [string ]string )
247+ for ncID , version := range nmaNCs {
248+ consolidatedNCs [ncID ] = version
249+ }
250+ for ncID , version := range imdsNCVersions {
251+ if _ , exists := consolidatedNCs [ncID ]; ! exists {
252+ consolidatedNCs [ncID ] = version
253+ }
254+ }
255+ hasNC .Set (float64 (len (consolidatedNCs )))
229256 for ncID := range outdatedNCs {
230- nmaNCVersionStr , ok := nmaNCs [ncID ]
257+ consolidatedNCVersionStr , ok := consolidatedNCs [ncID ]
231258 if ! ok {
232- // NMA doesn't have this NC that we need programmed yet, bail out
259+ // Neither NMA nor IMDS has this NC that we need programmed yet, bail out
233260 continue
234261 }
235- nmaNCVersion , err := strconv .Atoi (nmaNCVersionStr )
262+ consolidatedNCVersion , err := strconv .Atoi (consolidatedNCVersionStr )
236263 if err != nil {
237264 logger .Errorf ("failed to parse container version of %s: %s" , ncID , err )
238265 continue
@@ -245,7 +272,7 @@ func (service *HTTPRestService) syncHostNCVersion(ctx context.Context, channelMo
245272 return len (programmedNCs ), errors .Wrapf (errNonExistentContainerStatus , "can't find NC with ID %s in service state, stop updating this host NC version" , ncID )
246273 }
247274 // if the NC still exists in state and is programmed to some version (doesn't have to be latest), add it to our set of NCs that have been programmed
248- if nmaNCVersion > - 1 {
275+ if consolidatedNCVersion > - 1 {
249276 programmedNCs [ncID ] = struct {}{}
250277 }
251278
@@ -254,15 +281,15 @@ func (service *HTTPRestService) syncHostNCVersion(ctx context.Context, channelMo
254281 logger .Errorf ("failed to parse host nc version string %s: %s" , ncInfo .HostVersion , err )
255282 continue
256283 }
257- if localNCVersion > nmaNCVersion {
258- logger .Errorf ("NC version from NMA is decreasing: have %d, got %d" , localNCVersion , nmaNCVersion )
284+ if localNCVersion > consolidatedNCVersion {
285+ logger .Errorf ("NC version from consolidated sources is decreasing: have %d, got %d" , localNCVersion , consolidatedNCVersion )
259286 continue
260287 }
261288 if channelMode == cns .CRD {
262- service .MarkIpsAsAvailableUntransacted (ncInfo .ID , nmaNCVersion )
289+ service .MarkIpsAsAvailableUntransacted (ncInfo .ID , consolidatedNCVersion )
263290 }
264- logger .Printf ("Updating NC %s host version from %s to %s" , ncID , ncInfo .HostVersion , nmaNCVersionStr )
265- ncInfo .HostVersion = nmaNCVersionStr
291+ logger .Printf ("Updating NC %s host version from %s to %s" , ncID , ncInfo .HostVersion , consolidatedNCVersionStr )
292+ ncInfo .HostVersion = consolidatedNCVersionStr
266293 logger .Printf ("Updated NC %s host version to %s" , ncID , ncInfo .HostVersion )
267294 service .state .ContainerStatus [ncID ] = ncInfo
268295 // if we successfully updated the NC, pop it from the needs update set.
@@ -271,7 +298,7 @@ func (service *HTTPRestService) syncHostNCVersion(ctx context.Context, channelMo
271298 // if we didn't empty out the needs update set, NMA has not programmed all the NCs we are expecting, and we
272299 // need to return an error indicating that
273300 if len (outdatedNCs ) > 0 {
274- return len (programmedNCs ), errors .Errorf ("unabled to update some NCs: %v, missing or bad response from NMA" , outdatedNCs )
301+ return len (programmedNCs ), errors .Errorf ("unabled to update some NCs: %v, missing or bad response from NMA or ipam " , outdatedNCs )
275302 }
276303
277304 return len (programmedNCs ), nil
@@ -634,3 +661,59 @@ func (service *HTTPRestService) CreateOrUpdateNetworkContainerInternal(req *cns.
634661func (service * HTTPRestService ) SetVFForAccelnetNICs () error {
635662 return service .setVFForAccelnetNICs ()
636663}
664+
665+ // checkNMAgentAPISupport checks if specific APIs are supported by NMAgent using the existing client
666+ func (service * HTTPRestService ) checkNMAgentAPISupport (ctx context.Context ) (swiftV2Support bool , err error ) {
667+ // Use the existing NMAgent client instead of direct HTTP calls
668+ if service .nma == nil {
669+ return false , fmt .Errorf ("NMAgent client is not available" )
670+ }
671+
672+ apis , err := service .nma .SupportedAPIs (ctx )
673+ if err != nil {
674+ return false , fmt .Errorf ("failed to get supported APIs from NMAgent client: %w" , err )
675+ }
676+
677+ logger .Printf ("[checkNMAgentAPISupport] Found %d APIs from NMAgent client" , len (apis ))
678+ for i , api := range apis {
679+ logger .Printf ("[checkNMAgentAPISupport] API %d: %s" , i + 1 , api )
680+
681+ if strings .Contains (api , nmAgentSwiftV2API ) { // change
682+ swiftV2Support = true
683+ }
684+ }
685+
686+ logger .Printf ("[checkNMAgentAPISupport] Support check - SwiftV2: %t" , swiftV2Support )
687+ return swiftV2Support , nil
688+ }
689+
690+ // GetIMDSNCVersions gets NC versions from IMDS and returns them as a map
691+ func (service * HTTPRestService ) GetIMDSNCVersions (ctx context.Context ) (map [string ]string , error ) {
692+ logger .Printf ("[GetIMDSNCVersions] Getting NC versions from IMDS" )
693+
694+ // Check NMAgent API support for SwiftV2, if it fails return empty map assuming support might not be available in that nma build
695+ swiftV2Support , err := service .checkNMAgentAPISupport (ctx )
696+ if err != nil {
697+ logger .Printf ("[GetIMDSNCVersions] Failed to check NMAgent API support, returning empty map: %v" , err )
698+ return make (map [string ]string ), nil
699+ }
700+
701+ if ! swiftV2Support {
702+ logger .Printf ("[GetIMDSNCVersions] SwiftV2 API not supported, returning empty NC versions map" )
703+ return make (map [string ]string ), nil
704+ }
705+
706+ logger .Printf ("[GetIMDSNCVersions] SwiftV2 support API exists (%t), proceeding to get NC versions from IMDS" , swiftV2Support )
707+
708+ imdsClient := service .imdsClient
709+
710+ // Get all NC versions from IMDS
711+ ncVersions , err := imdsClient .GetNCVersionsFromIMDS (ctx )
712+ if err != nil {
713+ logger .Printf ("[GetIMDSNCVersions] Failed to get NC versions from IMDS: %v" , err )
714+ return make (map [string ]string ), nil
715+ }
716+
717+ logger .Printf ("[GetIMDSNCVersions] Successfully got %d NC versions from IMDS" , len (ncVersions ))
718+ return ncVersions , nil
719+ }
0 commit comments