Skip to content

Commit ba798ec

Browse files
rishupkclaude
andcommitted
feat(azure/rhel-ai): add list-versions subcommand
- Add ListGalleriesByPrefix to data/images.go — queries Azure Compute Gallery by resource group and name prefix using the SDK - Add ListVersions to the rhel-ai action — enumerates available RHEL AI image versions for a given accelerator type from the owner gallery - Add `mapt azure rhel-ai list-versions --accelerator <cuda|rocm>` cobra subcommand to expose version discovery via CLI - Extract imageOwnerResourceGroup constant from the hardcoded string in imageIdRegex Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Rishabh Kothari <rkothari@redhat.com>
1 parent aaa5c99 commit ba798ec

3 files changed

Lines changed: 87 additions & 3 deletions

File tree

cmd/mapt/cmd/azure/hosts/rhelai.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package hosts
22

33
import (
4+
"fmt"
5+
46
"github.com/redhat-developer/mapt/cmd/mapt/cmd/params"
57
maptContext "github.com/redhat-developer/mapt/pkg/manager/context"
68
rhelai "github.com/redhat-developer/mapt/pkg/provider/azure/action/rhel-ai"
@@ -13,6 +15,9 @@ import (
1315
const (
1416
cmdRHELAI = "rhel-ai"
1517
cmdRHELAIDesc = "manage rhel ai host"
18+
19+
cmdRHELAIListVersions = "list-versions"
20+
cmdRHELAIListVersionsDesc = "list available RHEL AI versions in the Azure Compute Gallery"
1621
)
1722

1823
func GetRHELAICmd() *cobra.Command {
@@ -31,7 +36,7 @@ func GetRHELAICmd() *cobra.Command {
3136
params.AddCommonFlags(flagSet)
3237
c.PersistentFlags().AddFlagSet(flagSet)
3338

34-
c.AddCommand(getRHELAICreate(), getRHELAIDestroy())
39+
c.AddCommand(getRHELAICreate(), getRHELAIDestroy(), getRHELAIListVersions())
3540
return c
3641
}
3742

@@ -104,3 +109,27 @@ func getRHELAIDestroy() *cobra.Command {
104109
c.PersistentFlags().AddFlagSet(flagSet)
105110
return c
106111
}
112+
113+
func getRHELAIListVersions() *cobra.Command {
114+
c := &cobra.Command{
115+
Use: cmdRHELAIListVersions,
116+
Short: cmdRHELAIListVersionsDesc,
117+
RunE: func(cmd *cobra.Command, args []string) error {
118+
if err := viper.BindPFlags(cmd.Flags()); err != nil {
119+
return err
120+
}
121+
versions, err := rhelai.ListVersions(cmd.Context(), viper.GetString(params.RhelAIAccelerator))
122+
if err != nil {
123+
return err
124+
}
125+
for _, v := range versions {
126+
fmt.Println(v)
127+
}
128+
return nil
129+
},
130+
}
131+
flagSet := pflag.NewFlagSet(cmdRHELAIListVersions, pflag.ExitOnError)
132+
flagSet.StringP(params.RhelAIAccelerator, "", params.RhelAIAccelearatorDefault, params.RhelAIAccelearatorDesc)
133+
c.PersistentFlags().AddFlagSet(flagSet)
134+
return c
135+
}

pkg/provider/azure/action/rhel-ai/rhelai.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package rhelai
33
import (
44
"context"
55
"fmt"
6+
"sort"
67
"strings"
78

89
maptContext "github.com/redhat-developer/mapt/pkg/manager/context"
@@ -15,10 +16,11 @@ import (
1516

1617
const (
1718
imageOwnerSubscriptionId = "02db6bd4-035c-4074-b699-468f3d914744"
19+
imageOwnerResourceGroup = "aipcc-productization"
1820
// $1 accelerator $2 version
1921
imageNameRegex = "rhel-ai-%s-azure-%s"
20-
// $1 subscriptionId $2 rgName
21-
imageIdRegex = "/subscriptions/%s/resourceGroups/aipcc-productization/providers/Microsoft.Compute/galleries/%s/images/%s/versions/1.0.0"
22+
// $1 subscriptionId $2 rgName $3 galleryName $4 imageName
23+
imageIdRegex = "/subscriptions/%s/resourceGroups/" + imageOwnerResourceGroup + "/providers/Microsoft.Compute/galleries/%s/images/%s/versions/1.0.0"
2224

2325
username = "azureuser"
2426
)
@@ -104,3 +106,28 @@ func Create(mCtxArgs *maptContext.ContextArgs, args *apiRHELAI.RHELAIArgs) (err
104106
func Destroy(mCtxArgs *maptContext.ContextArgs) error {
105107
return azureLinux.Destroy(mCtxArgs)
106108
}
109+
110+
// ListVersions returns available RHEL AI version strings for the given accelerator,
111+
// sorted in ascending order. Versions are derived from Azure Compute Gallery names
112+
// in the image owner's subscription (e.g. gallery "rhel_ai_cuda_azure_3.4.0_ea.2"
113+
// yields version "3.4.0-ea.2").
114+
func ListVersions(ctx context.Context, accelerator string) ([]string, error) {
115+
acc := strings.ToLower(strings.TrimSpace(accelerator))
116+
switch acc {
117+
case "cuda", "rocm":
118+
default:
119+
return nil, fmt.Errorf("unsupported accelerator %q (expected: cuda or rocm)", accelerator)
120+
}
121+
prefix := fmt.Sprintf("rhel_ai_%s_azure_", strings.ReplaceAll(acc, "-", "_"))
122+
galleries, err := data.ListGalleriesByPrefix(ctx, imageOwnerSubscriptionId, imageOwnerResourceGroup, prefix)
123+
if err != nil {
124+
return nil, fmt.Errorf("listing RHEL AI versions for accelerator %q: %w", accelerator, err)
125+
}
126+
versions := make([]string, 0, len(galleries))
127+
for _, g := range galleries {
128+
raw := strings.TrimPrefix(g, prefix)
129+
versions = append(versions, strings.ReplaceAll(raw, "_", "-"))
130+
}
131+
sort.Strings(versions)
132+
return versions, nil
133+
}

pkg/provider/azure/data/images.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,34 @@ func GetSharedImageDiskControllerTypes(ctx context.Context, id *string) ([]strin
120120
return nil, nil
121121
}
122122

123+
// ListGalleriesByPrefix returns the names of galleries in resourceGroup (within
124+
// subscriptionID) whose names start with namePrefix.
125+
func ListGalleriesByPrefix(ctx context.Context, subscriptionID, resourceGroup, namePrefix string) ([]string, error) {
126+
ensureAzureEnvs()
127+
cred, err := azidentity.NewDefaultAzureCredential(nil)
128+
if err != nil {
129+
return nil, err
130+
}
131+
c, err := armcompute.NewClientFactory(subscriptionID, cred, nil)
132+
if err != nil {
133+
return nil, err
134+
}
135+
pager := c.NewGalleriesClient().NewListByResourceGroupPager(resourceGroup, nil)
136+
var names []string
137+
for pager.More() {
138+
page, err := pager.NextPage(ctx)
139+
if err != nil {
140+
return nil, err
141+
}
142+
for _, g := range page.Value {
143+
if g.Name != nil && strings.HasPrefix(*g.Name, namePrefix) {
144+
names = append(names, *g.Name)
145+
}
146+
}
147+
}
148+
return names, nil
149+
}
150+
123151
func SkuG2Support(ctx context.Context, location string, publisher string, offer string, sku string) (string, error) {
124152
ensureAzureEnvs()
125153
cred, err := azidentity.NewDefaultAzureCredential(nil)

0 commit comments

Comments
 (0)