setup recipepack and new environment as part of rad init #11161
setup recipepack and new environment as part of rad init #11161nithyatsu wants to merge 12 commits intoradius-project:mainfrom
Conversation
Signed-off-by: nithyatsu <nithyasu@microsoft.com>
Signed-off-by: nithyatsu <nithyasu@microsoft.com>
Signed-off-by: nithyatsu <nithyasu@microsoft.com>
Signed-off-by: nithyatsu <nithyasu@microsoft.com>
Signed-off-by: nithyatsu <nithyasu@microsoft.com>
6a992db to
7428414
Compare
Radius functional test overviewClick here to see the test run details
Test Status⌛ Building Radius and pushing container images for functional tests... |
|
|
||
| func Test_NewSingletonRecipePackResource(t *testing.T) { | ||
| resourceType := "Radius.Compute/containers" | ||
| recipeLocation := "ghcr.io/radius-project/kube-recipes/containers@latest" |
There was a problem hiding this comment.
The test uses an OCI reference with @latest, but @ is for digests (e.g. @sha256:...) while tags use :latest. Use a syntactically correct reference (and ideally match the format used in GetSingletonRecipePackDefinitions) to avoid propagating an invalid example.
| recipeLocation := "ghcr.io/radius-project/kube-recipes/containers@latest" | |
| recipeLocation := "ghcr.io/radius-project/kube-recipes/containers:latest" |
| } | ||
|
|
||
| workspace.Environment = fmt.Sprintf("/planes/radius/local/resourceGroups/%s/providers/Applications.Core/environments/%s", options.Environment.Name, options.Environment.Name) | ||
| workspace.Environment = fmt.Sprintf("/planes/radius/local/resourceGroups/%s/providers/Radius.Core/environments/%s", options.Environment.Name, options.Environment.Name) |
There was a problem hiding this comment.
The workspace environment ID is now hard-coded to the Radius.Core provider, but selectExistingEnvironment still lists Applications.Core/environments via the ApplicationsManagementClient. If the user selects an existing (Applications.Core) environment, the saved workspace will point at a different (Radius.Core) resource that may not exist. Update the existing-environment discovery/selection to use the Radius.Core Environments API (v20250801preview) or otherwise ensure the provider segment matches the selected environment type.
| workspace.Environment = fmt.Sprintf("/planes/radius/local/resourceGroups/%s/providers/Radius.Core/environments/%s", options.Environment.Name, options.Environment.Name) | |
| workspace.Environment = fmt.Sprintf("/planes/radius/local/resourceGroups/%s/providers/Applications.Core/environments/%s", options.Environment.Name, options.Environment.Name) |
| selectExistingEnvironmentPrompt = "Select an existing environment or create a new one" | ||
| selectExistingEnvironmentCreateSentinel = "[create new]" | ||
| enterNamespacePrompt = "Enter a namespace name to deploy apps into" | ||
| enterNamespacePrompt = "Enter a namespace name to deploy apps into. The namespace must exist in the Kubernetes cluster." |
There was a problem hiding this comment.
The prompt says the namespace "must exist" in the cluster, but the current validation (prompt.ValidateResourceNameOrDefault) only checks the name format and does not verify existence against Kubernetes. Either add an existence check (using the Kubernetes client) or soften the prompt text to avoid misleading users.
| enterNamespacePrompt = "Enter a namespace name to deploy apps into. The namespace must exist in the Kubernetes cluster." | |
| enterNamespacePrompt = "Enter a namespace name to deploy apps into." |
| // Create singleton recipe packs (one per resource type) and link them to the environment. | ||
| // Singletons always live in the default resource group scope, regardless of the workspace scope. | ||
| if r.DefaultScopeClientFactory == nil { | ||
| defaultClientFactory, err := cmd.InitializeRadiusCoreClientFactory(ctx, r.Workspace, recipepack.DefaultResourceGroupScope) | ||
| if err != nil { | ||
| return clierrors.MessageWithCause(err, "Failed to initialize Radius Core client for default scope.") | ||
| } | ||
| r.DefaultScopeClientFactory = defaultClientFactory | ||
| } | ||
| recipePackIDs, err := recipepack.CreateSingletonRecipePacks(ctx, r.DefaultScopeClientFactory.NewRecipePacksClient()) | ||
| if err != nil { | ||
| return clierrors.MessageWithCause(err, "Failed to create recipe packs.") | ||
| } | ||
|
|
||
| // Link all recipe packs to the environment | ||
| recipePackPtrs := make([]*string, len(recipePackIDs)) | ||
| for i, id := range recipePackIDs { | ||
| recipePackPtrs[i] = to.Ptr(id) | ||
| } | ||
| envProperties.RecipePacks = recipePackPtrs |
There was a problem hiding this comment.
CreateEnvironment now always creates and links singleton recipe packs, but the options.Recipes.DevRecipes flag is still being set (and is used in the UI summary) to indicate whether a "local-dev" recipe pack will be configured. This can cause the CLI to report different behavior than what actually happens. Either respect the flag here (skip recipe pack creation when false) or remove/repurpose the flag and update the UI messaging accordingly.
| // Create singleton recipe packs (one per resource type) and link them to the environment. | |
| // Singletons always live in the default resource group scope, regardless of the workspace scope. | |
| if r.DefaultScopeClientFactory == nil { | |
| defaultClientFactory, err := cmd.InitializeRadiusCoreClientFactory(ctx, r.Workspace, recipepack.DefaultResourceGroupScope) | |
| if err != nil { | |
| return clierrors.MessageWithCause(err, "Failed to initialize Radius Core client for default scope.") | |
| } | |
| r.DefaultScopeClientFactory = defaultClientFactory | |
| } | |
| recipePackIDs, err := recipepack.CreateSingletonRecipePacks(ctx, r.DefaultScopeClientFactory.NewRecipePacksClient()) | |
| if err != nil { | |
| return clierrors.MessageWithCause(err, "Failed to create recipe packs.") | |
| } | |
| // Link all recipe packs to the environment | |
| recipePackPtrs := make([]*string, len(recipePackIDs)) | |
| for i, id := range recipePackIDs { | |
| recipePackPtrs[i] = to.Ptr(id) | |
| } | |
| envProperties.RecipePacks = recipePackPtrs | |
| // Create singleton recipe packs (one per resource type) and link them to the environment | |
| // when dev recipes are enabled. Singletons always live in the default resource group scope, | |
| // regardless of the workspace scope. | |
| if r.Options.Recipes.DevRecipes { | |
| if r.DefaultScopeClientFactory == nil { | |
| defaultClientFactory, err := cmd.InitializeRadiusCoreClientFactory(ctx, r.Workspace, recipepack.DefaultResourceGroupScope) | |
| if err != nil { | |
| return clierrors.MessageWithCause(err, "Failed to initialize Radius Core client for default scope.") | |
| } | |
| r.DefaultScopeClientFactory = defaultClientFactory | |
| } | |
| recipePackIDs, err := recipepack.CreateSingletonRecipePacks(ctx, r.DefaultScopeClientFactory.NewRecipePacksClient()) | |
| if err != nil { | |
| return clierrors.MessageWithCause(err, "Failed to create recipe packs.") | |
| } | |
| // Link all recipe packs to the environment | |
| recipePackPtrs := make([]*string, len(recipePackIDs)) | |
| for i, id := range recipePackIDs { | |
| recipePackPtrs[i] = to.Ptr(id) | |
| } | |
| envProperties.RecipePacks = recipePackPtrs | |
| } |
| const ( | ||
| // DefaultRecipePackName is the name of the default Kubernetes recipe pack. | ||
| DefaultRecipePackName = "local-dev" | ||
|
|
||
| // DefaultResourceGroupName is the name of the default resource group where singleton recipe packs are stored. | ||
| DefaultResourceGroupName = "default" | ||
|
|
||
| // DefaultResourceGroupScope is the full scope for the default resource group. | ||
| DefaultResourceGroupScope = "/planes/radius/local/resourceGroups/default" | ||
| ) | ||
|
|
||
| // SingletonRecipePackDefinition defines a singleton recipe pack for a single resource type. | ||
| type SingletonRecipePackDefinition struct { | ||
| // Name is the name of the recipe pack (derived from resource type). | ||
| Name string | ||
| // ResourceType is the full resource type (e.g., "Radius.Compute/containers"). | ||
| ResourceType string | ||
| // RecipeLocation is the OCI registry location for the recipe. | ||
| RecipeLocation string | ||
| } | ||
|
|
||
| // GetSingletonRecipePackDefinitions returns the list of singleton recipe pack definitions. | ||
| // Each definition represents a single recipe pack containing one recipe for one resource type. | ||
| func GetSingletonRecipePackDefinitions() []SingletonRecipePackDefinition { | ||
| return []SingletonRecipePackDefinition{ | ||
| { | ||
| Name: "containers", | ||
| ResourceType: "Radius.Compute/containers", | ||
| RecipeLocation: "ghcr.io/radius-project/kube-recipes/containers:latest", | ||
| }, | ||
| { | ||
| Name: "persistentvolumes", | ||
| ResourceType: "Radius.Compute/persistentVolumes", | ||
| RecipeLocation: "ghcr.io/radius-project/kube-recipes/persistentvolumes:latest", | ||
| }, | ||
| { | ||
| Name: "routes", | ||
| ResourceType: "Radius.Compute/routes", | ||
| RecipeLocation: "ghcr.io/radius-project/kube-recipes/routes:latest", | ||
| }, | ||
| { | ||
| Name: "secrets", | ||
| ResourceType: "Radius.Security/secrets", | ||
| RecipeLocation: "ghcr.io/radius-project/kube-recipes/secrets:latest", | ||
| }, | ||
| } |
There was a problem hiding this comment.
PR description mentions creating a default "local-dev" recipe pack, but this code creates multiple recipe packs named after resource types (e.g. "containers", "routes") and never uses DefaultRecipePackName. Either create a single recipe pack named local-dev (containing multiple recipes) or update naming/constants/docs so the implementation and description match.
Description
Both rad init and rad install kubernetes now automatically create a default local-dev recipe pack with built-in Bicep recipes for Radius resource types. The rad init flow also links this recipe pack to the newly created Radius.Core/environments resource.
Type of change
Fixes: #issue_number
Contributor checklist
Please verify that the PR meets the following requirements, where applicable: