@@ -1265,11 +1265,9 @@ func (c *NebiusClient) buildDiskCreateRequest(ctx context.Context, diskName stri
12651265 return nil , fmt .Errorf ("could not resolve image %s to either a working family or image ID: %w" , attrs .ImageID , err )
12661266}
12671267
1268- // getWorkingPublicImageID gets a working public image ID based on the requested image type
1269- //
1270- //nolint:gocognit,gocyclo // Complex function trying multiple image resolution strategies
1268+ // getWorkingPublicImageID gets a working public image ID based on the requested image type.
1269+ // It scores every non-ARM64 image and returns the highest-scored one, this is done to handle change in ordering of images from nebius api.
12711270func (c * NebiusClient ) getWorkingPublicImageID (ctx context.Context , requestedImage string ) (string , error ) {
1272- // Get available public images from the correct region
12731271 publicImagesParent := c .getPublicImagesParent ()
12741272 imagesResp , err := c .sdk .Services ().Compute ().V1 ().Image ().List (ctx , & compute.ListImagesRequest {
12751273 ParentId : publicImagesParent ,
@@ -1282,67 +1280,83 @@ func (c *NebiusClient) getWorkingPublicImageID(ctx context.Context, requestedIma
12821280 return "" , fmt .Errorf ("no public images available" )
12831281 }
12841282
1285- // Try to find the best match based on the requested image
12861283 requestedLower := strings .ToLower (requestedImage )
12871284
1288- var bestMatch * compute.Image
1289- var fallbackImage * compute. Image
1285+ var bestImage * compute.Image
1286+ bestScore := - 1
12901287
12911288 for _ , image := range imagesResp .GetItems () {
12921289 if image .Metadata == nil {
12931290 continue
12941291 }
1295-
12961292 if image .Spec != nil && image .Spec .GetCpuArchitecture () == compute .ImageSpec_ARM64 {
12971293 continue
12981294 }
12991295
1300- imageName := strings .ToLower (image .Metadata .Name )
1301-
1302- // Set fallback to first available image
1303- if fallbackImage == nil {
1304- fallbackImage = image
1296+ score := scoreImage (image , requestedLower )
1297+ if score > bestScore {
1298+ bestScore = score
1299+ bestImage = image
13051300 }
1301+ }
13061302
1307- // Look for Ubuntu matches
1308- if strings .Contains (requestedLower , "ubuntu" ) && strings .Contains (imageName , "ubuntu" ) {
1309- // Prefer specific version matches
1310- //nolint:gocritic // if-else chain is clearer than switch for version matching logic
1311- if strings .Contains (requestedLower , "24.04" ) || strings .Contains (requestedLower , "24" ) {
1312- if strings .Contains (imageName , "ubuntu24.04" ) {
1313- bestMatch = image
1314- break
1315- }
1316- } else if strings .Contains (requestedLower , "22.04" ) || strings .Contains (requestedLower , "22" ) {
1317- if strings .Contains (imageName , "ubuntu22.04" ) {
1318- bestMatch = image
1319- break
1320- }
1321- } else if strings .Contains (requestedLower , "20.04" ) || strings .Contains (requestedLower , "20" ) {
1322- if strings .Contains (imageName , "ubuntu20.04" ) {
1323- bestMatch = image
1324- break
1325- }
1326- }
1303+ if bestImage == nil {
1304+ return "" , fmt .Errorf ("no suitable public image found" )
1305+ }
1306+
1307+ return bestImage .Metadata .Id , nil
1308+ }
13271309
1328- // Any Ubuntu image is better than non-Ubuntu
1329- if bestMatch == nil {
1330- bestMatch = image
1310+ // scoreImage assigns a priority score to an image. Higher score = better match.
1311+ // When requestedImage is empty (default deploy), the function uses a standard
1312+ // preference order: Ubuntu 24 CUDA 13 > Ubuntu 24 CUDA 12 > Ubuntu 22 CUDA 12
1313+ // > Ubuntu 24 driverless > any Ubuntu > worker node > anything else.
1314+ // When requestedImage is non-empty, exact family/name matches get a bonus.
1315+ func scoreImage (image * compute.Image , requestedLower string ) int {
1316+ family := ""
1317+ if image .Spec != nil {
1318+ family = strings .ToLower (image .Spec .GetImageFamily ())
1319+ }
1320+ name := strings .ToLower (image .Metadata .Name )
1321+
1322+ isWorkerNode := strings .Contains (family , "mk8s-worker" ) || strings .Contains (name , "worker-node" )
1323+ isUbuntu := strings .Contains (family , "ubuntu" ) || strings .Contains (name , "ubuntu" )
1324+ hasCuda13 := strings .Contains (family , "cuda13" ) || strings .Contains (name , "cuda13" )
1325+ hasCuda12 := strings .Contains (family , "cuda12" ) || strings .Contains (name , "cuda12" )
1326+ isUbuntu24 := strings .Contains (family , "ubuntu24" ) || strings .Contains (name , "ubuntu24" )
1327+ isUbuntu22 := strings .Contains (family , "ubuntu22" ) || strings .Contains (name , "ubuntu22" )
1328+
1329+ score := 1 // baseline for any non-ARM64 image
1330+
1331+ if isWorkerNode {
1332+ score = 10
1333+ } else if isUbuntu {
1334+ score = 50
1335+ if isUbuntu24 {
1336+ score = 60
1337+ if hasCuda13 {
1338+ score = 100
1339+ } else if hasCuda12 {
1340+ score = 90
1341+ }
1342+ } else if isUbuntu22 {
1343+ score = 55
1344+ if hasCuda12 {
1345+ score = 80
13311346 }
13321347 }
13331348 }
13341349
1335- // Use best match if found, otherwise fallback
1336- selectedImage := bestMatch
1337- if selectedImage == nil {
1338- selectedImage = fallbackImage
1339- }
1340-
1341- if selectedImage == nil {
1342- return "" , fmt .Errorf ("no suitable public image found" )
1350+ // If the caller explicitly requested something, boost images that match the request
1351+ if requestedLower != "" {
1352+ if strings .Contains (name , requestedLower ) || strings .Contains (family , requestedLower ) || requestedLower == family {
1353+ score += 200
1354+ } else if isUbuntu && strings .Contains (requestedLower , "ubuntu" ) {
1355+ score += 50
1356+ }
13431357 }
13441358
1345- return selectedImage . Metadata . Id , nil
1359+ return score
13461360}
13471361
13481362// getPublicImagesParent determines the correct public images parent ID based on project routing code
0 commit comments