@@ -15,7 +15,9 @@ import (
1515)
1616
1717const (
18- platformTypeCPU = "cpu"
18+ platformTypeCPU = "cpu"
19+ nebiusGPUImageFamily = "ubuntu24.04-cuda13.0"
20+ nebiusCPUImageFamily = "ubuntu24.04-driverless"
1921)
2022
2123//nolint:gocyclo,funlen // Complex instance creation with resource management
@@ -1151,10 +1153,7 @@ func (c *NebiusClient) createBootDisk(ctx context.Context, attrs v1.CreateInstan
11511153 diskName := fmt .Sprintf ("%s-boot-disk" , attrs .RefID )
11521154
11531155 // Try to use image family first, then fallback to specific image ID
1154- createReq , err := c .buildDiskCreateRequest (ctx , diskName , attrs )
1155- if err != nil {
1156- return "" , fmt .Errorf ("failed to build disk create request: %w" , err )
1157- }
1156+ createReq := c .buildDiskCreateRequest (ctx , diskName , attrs )
11581157
11591158 operation , err := c .sdk .Services ().Compute ().V1 ().Disk ().Create (ctx , createReq )
11601159 if err != nil {
@@ -1180,12 +1179,14 @@ func (c *NebiusClient) createBootDisk(ctx context.Context, attrs v1.CreateInstan
11801179 return diskID , nil
11811180}
11821181
1183- // buildDiskCreateRequest builds a disk creation request, trying image family first, then image ID
1184- func (c * NebiusClient ) buildDiskCreateRequest (ctx context.Context , diskName string , attrs v1.CreateInstanceAttrs ) ( * compute.CreateDiskRequest , error ) {
1182+ // buildDiskCreateRequest builds a disk creation request using the fixed Nebius image family for the instance type.
1183+ func (c * NebiusClient ) buildDiskCreateRequest (_ context.Context , diskName string , attrs v1.CreateInstanceAttrs ) * compute.CreateDiskRequest {
11851184 if attrs .DiskSize == 0 {
11861185 attrs .DiskSize = 1280 * units .Gibibyte // Defaulted by the Nebius Console
11871186 }
11881187
1188+ imageFamily := getNebiusBootImageFamily (attrs .InstanceType )
1189+
11891190 baseReq := & compute.CreateDiskRequest {
11901191 Metadata : & common.ResourceMetadata {
11911192 ParentId : c .projectID ,
@@ -1194,148 +1195,45 @@ func (c *NebiusClient) buildDiskCreateRequest(ctx context.Context, diskName stri
11941195 "created-by" : "brev-cloud-sdk" ,
11951196 "brev-user" : c .refID ,
11961197 "environment-id" : attrs .RefID ,
1198+ "image-family" : imageFamily ,
11971199 },
11981200 },
11991201 Spec : & compute.DiskSpec {
12001202 Size : & compute.DiskSpec_SizeGibibytes {
12011203 SizeGibibytes : int64 (attrs .DiskSize / units .Gibibyte ),
12021204 },
12031205 Type : compute .DiskSpec_NETWORK_SSD ,
1204- },
1205- }
1206-
1207- // First, try to resolve and use image family
1208- if imageFamily , err := c .resolveImageFamily (ctx , attrs .ImageID ); err == nil {
1209- publicImagesParent := c .getPublicImagesParent ()
1210-
1211- // Skip validation for known-good common families to speed up instance start
1212- knownFamilies := []string {"ubuntu22.04-cuda12" , "mk8s-worker-node-v-1-32-ubuntu24.04" , "mk8s-worker-node-v-1-32-ubuntu24.04-cuda12.8" }
1213- isKnownFamily := false
1214- for _ , known := range knownFamilies {
1215- if imageFamily == known {
1216- isKnownFamily = true
1217- break
1218- }
1219- }
1220-
1221- if isKnownFamily {
1222- // Use known family without validation
1223- baseReq .Spec .Source = & compute.DiskSpec_SourceImageFamily {
1206+ Source : & compute.DiskSpec_SourceImageFamily {
12241207 SourceImageFamily : & compute.SourceImageFamily {
12251208 ImageFamily : imageFamily ,
1226- ParentId : publicImagesParent ,
1209+ ParentId : c . getPublicImagesParent () ,
12271210 },
1228- }
1229- baseReq .Metadata .Labels ["image-family" ] = imageFamily
1230- return baseReq , nil
1231- }
1232-
1233- // For unknown families, validate first
1234- _ , err := c .sdk .Services ().Compute ().V1 ().Image ().GetLatestByFamily (ctx , & compute.GetImageLatestByFamilyRequest {
1235- ParentId : publicImagesParent ,
1236- ImageFamily : imageFamily ,
1237- })
1238- if err == nil {
1239- // Family works, use it
1240- baseReq .Spec .Source = & compute.DiskSpec_SourceImageFamily {
1241- SourceImageFamily : & compute.SourceImageFamily {
1242- ImageFamily : imageFamily ,
1243- ParentId : publicImagesParent ,
1244- },
1245- }
1246- baseReq .Metadata .Labels ["image-family" ] = imageFamily
1247- return baseReq , nil
1248- }
1249- }
1250-
1251- // Family approach failed, try to use a known working public image ID
1252- publicImageID , err := c .getWorkingPublicImageID (ctx , attrs .ImageID )
1253- if err == nil {
1254- baseReq .Spec .Source = & compute.DiskSpec_SourceImageId {
1255- SourceImageId : publicImageID ,
1256- }
1257- baseReq .Metadata .Labels ["source-image-id" ] = publicImageID
1258- return baseReq , nil
1211+ },
1212+ },
12591213 }
12601214
1261- // Both approaches failed
1262- return nil , fmt .Errorf ("could not resolve image %s to either a working family or image ID: %w" , attrs .ImageID , err )
1215+ return baseReq
12631216}
12641217
1265- // getWorkingPublicImageID gets a working public image ID based on the requested image type
1266- //
1267- //nolint:gocognit,gocyclo // Complex function trying multiple image resolution strategies
1268- func (c * NebiusClient ) getWorkingPublicImageID (ctx context.Context , requestedImage string ) (string , error ) {
1269- // Get available public images from the correct region
1270- publicImagesParent := c .getPublicImagesParent ()
1271- imagesResp , err := c .sdk .Services ().Compute ().V1 ().Image ().List (ctx , & compute.ListImagesRequest {
1272- ParentId : publicImagesParent ,
1273- })
1274- if err != nil {
1275- return "" , fmt .Errorf ("failed to list public images: %w" , err )
1276- }
1277-
1278- if len (imagesResp .GetItems ()) == 0 {
1279- return "" , fmt .Errorf ("no public images available" )
1280- }
1281-
1282- // Try to find the best match based on the requested image
1283- requestedLower := strings .ToLower (requestedImage )
1284-
1285- var bestMatch * compute.Image
1286- var fallbackImage * compute.Image
1287-
1288- for _ , image := range imagesResp .GetItems () {
1289- if image .Metadata == nil {
1290- continue
1291- }
1292-
1293- imageName := strings .ToLower (image .Metadata .Name )
1294-
1295- // Set fallback to first available image
1296- if fallbackImage == nil {
1297- fallbackImage = image
1298- }
1299-
1300- // Look for Ubuntu matches
1301- if strings .Contains (requestedLower , "ubuntu" ) && strings .Contains (imageName , "ubuntu" ) {
1302- // Prefer specific version matches
1303- //nolint:gocritic // if-else chain is clearer than switch for version matching logic
1304- if strings .Contains (requestedLower , "24.04" ) || strings .Contains (requestedLower , "24" ) {
1305- if strings .Contains (imageName , "ubuntu24.04" ) {
1306- bestMatch = image
1307- break
1308- }
1309- } else if strings .Contains (requestedLower , "22.04" ) || strings .Contains (requestedLower , "22" ) {
1310- if strings .Contains (imageName , "ubuntu22.04" ) {
1311- bestMatch = image
1312- break
1313- }
1314- } else if strings .Contains (requestedLower , "20.04" ) || strings .Contains (requestedLower , "20" ) {
1315- if strings .Contains (imageName , "ubuntu20.04" ) {
1316- bestMatch = image
1317- break
1318- }
1319- }
1320-
1321- // Any Ubuntu image is better than non-Ubuntu
1322- if bestMatch == nil {
1323- bestMatch = image
1324- }
1325- }
1218+ func getNebiusBootImageFamily (instanceType string ) string {
1219+ if isNebiusGPUInstanceType (instanceType ) {
1220+ return nebiusGPUImageFamily
13261221 }
1222+ return nebiusCPUImageFamily
1223+ }
13271224
1328- // Use best match if found, otherwise fallback
1329- selectedImage := bestMatch
1330- if selectedImage == nil {
1331- selectedImage = fallbackImage
1225+ func isNebiusGPUInstanceType ( instanceType string ) bool {
1226+ instanceTypeLower := strings . ToLower ( instanceType )
1227+ if instanceTypeLower == "" {
1228+ return false
13321229 }
13331230
1334- if selectedImage == nil {
1335- return "" , fmt .Errorf ("no suitable public image found" )
1231+ // GPU instance types start with "gpu-" (see getInstanceTypesForLocation)
1232+ if strings .HasPrefix (instanceTypeLower , "gpu-" ) {
1233+ return true
13361234 }
13371235
1338- return selectedImage . Metadata . Id , nil
1236+ return false
13391237}
13401238
13411239// getPublicImagesParent determines the correct public images parent ID based on project routing code
@@ -1575,73 +1473,6 @@ func (c *NebiusClient) parseInstanceType(ctx context.Context, instanceTypeID str
15751473 return "" , "" , fmt .Errorf ("could not parse instance type %s or find suitable platform/preset" , instanceTypeID )
15761474}
15771475
1578- // resolveImageFamily resolves an ImageID to an image family name
1579- // If ImageID is already a family name, use it directly
1580- // Otherwise, try to get the image and extract its family
1581- //
1582- //nolint:gocyclo,unparam // Complex image family resolution with fallback logic
1583- func (c * NebiusClient ) resolveImageFamily (ctx context.Context , imageID string ) (string , error ) {
1584- // Common Nebius image families - if ImageID matches one of these, use it directly
1585- commonFamilies := []string {
1586- "ubuntu22.04-cuda12" ,
1587- "mk8s-worker-node-v-1-32-ubuntu24.04" ,
1588- "mk8s-worker-node-v-1-32-ubuntu24.04-cuda12.8" ,
1589- "mk8s-worker-node-v-1-31-ubuntu24.04-cuda12" ,
1590- "ubuntu22.04" ,
1591- "ubuntu20.04" ,
1592- }
1593-
1594- // Check if ImageID is already a known family name
1595- for _ , family := range commonFamilies {
1596- if imageID == family {
1597- return family , nil
1598- }
1599- }
1600-
1601- // If ImageID looks like a family name pattern (contains dots, dashes, no UUIDs)
1602- // and doesn't look like a UUID, assume it's a family name
1603- if ! strings .Contains (imageID , "-" ) || len (imageID ) < 32 {
1604- // Likely a family name, use it directly
1605- return imageID , nil
1606- }
1607-
1608- // If it looks like a UUID/ID, try to get the image and extract its family
1609- image , err := c .sdk .Services ().Compute ().V1 ().Image ().Get (ctx , & compute.GetImageRequest {
1610- Id : imageID ,
1611- })
1612- if err != nil {
1613- // If we can't get the image, try using the ID as a family name anyway
1614- // This allows for custom family names that don't match our patterns
1615- return imageID , nil
1616- }
1617-
1618- // Extract family from image metadata/labels if available
1619- if image .Metadata != nil && image .Metadata .Labels != nil {
1620- if family , exists := image .Metadata .Labels ["family" ]; exists && family != "" {
1621- return family , nil
1622- }
1623- if family , exists := image .Metadata .Labels ["image-family" ]; exists && family != "" {
1624- return family , nil
1625- }
1626- }
1627-
1628- // Extract family from image name as fallback
1629- if image .Metadata != nil && image .Metadata .Name != "" {
1630- // Try to extract a reasonable family name from the image name
1631- name := strings .ToLower (image .Metadata .Name )
1632- if strings .Contains (name , "ubuntu22" ) || strings .Contains (name , "ubuntu-22" ) {
1633- return "ubuntu22.04" , nil
1634- }
1635- if strings .Contains (name , "ubuntu20" ) || strings .Contains (name , "ubuntu-20" ) {
1636- return "ubuntu20.04" , nil
1637- }
1638- }
1639-
1640- // Default fallback - use the original ImageID as family
1641- // This handles cases where users provide custom family names
1642- return imageID , nil
1643- }
1644-
16451476// deleteBootDisk deletes a boot disk by ID
16461477func (c * NebiusClient ) deleteBootDisk (ctx context.Context , diskID string ) error {
16471478 operation , err := c .sdk .Services ().Compute ().V1 ().Disk ().Delete (ctx , & compute.DeleteDiskRequest {
0 commit comments