-
Notifications
You must be signed in to change notification settings - Fork 123
Update radius to setup default recipepack during rad init and env operations. #11294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
33c9757
bcf50c6
c949d38
10ee0ce
5df98db
aaf64e4
4ca973a
67c7d0f
6e95956
c904431
0f24bf9
f3d8c7b
933cb9c
2ec7656
da4a68d
b00a62a
e204475
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,7 @@ import ( | |
| "github.com/radius-project/radius/pkg/cli/filesystem" | ||
| "github.com/radius-project/radius/pkg/cli/framework" | ||
| "github.com/radius-project/radius/pkg/cli/output" | ||
| "github.com/radius-project/radius/pkg/cli/recipepack" | ||
| "github.com/radius-project/radius/pkg/cli/workspaces" | ||
| "github.com/radius-project/radius/pkg/corerp/api/v20231001preview" | ||
| "github.com/radius-project/radius/pkg/corerp/api/v20250801preview" | ||
|
|
@@ -136,6 +137,9 @@ type Runner struct { | |
| RadiusCoreClientFactory *v20250801preview.ClientFactory | ||
| Deploy deploy.Interface | ||
| Output output.Interface | ||
| // DefaultScopeClientFactory is the client factory scoped to the default resource group. | ||
| // Recipe packs are always created/queried in the default scope. | ||
| DefaultScopeClientFactory *v20250801preview.ClientFactory | ||
|
|
||
| ApplicationName string | ||
| EnvironmentNameOrID string | ||
|
|
@@ -345,6 +349,14 @@ func (r *Runner) Run(ctx context.Context) error { | |
| "Deployment In Progress... ", r.FilePath, r.ApplicationName, r.EnvironmentNameOrID, r.Workspace.Name) | ||
| } | ||
|
|
||
| // Before deploying, set up recipe packs for any Radius.Core environments in the | ||
| // template. This creates default recipe pack resource if not found and injects its | ||
| // ID into the template. | ||
| err = r.setupRecipePack(ctx, template) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| _, err = r.Deploy.DeployWithProgress(ctx, deploy.Options{ | ||
| ConnectionFactory: r.ConnectionFactory, | ||
| Workspace: *r.Workspace, | ||
|
|
@@ -650,6 +662,157 @@ func (r *Runner) setupCloudProviders(properties any) { | |
| } | ||
| } | ||
|
|
||
| // setupRecipePack ensures recipe pack(s) for all Radius.Core/environments resources in the template. | ||
| // If a Radius.Core environment resource has no recipe | ||
| // packs set by the user, Radius creates(if needed) and fetches the default recipe pack from the default scope and | ||
| // injects its ID into the template. If the environment already has any recipe pack | ||
| // IDs set (literal or Bicep expression references), no changes are made. | ||
| func (r *Runner) setupRecipePack(ctx context.Context, template map[string]any) error { | ||
| envResources := findRadiusCoreEnvironmentResources(template) | ||
| if len(envResources) == 0 { | ||
| return nil | ||
| } | ||
|
|
||
| for _, envResource := range envResources { | ||
| if err := r.setupRecipePackForEnvironment(ctx, envResource); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // setupRecipePackForEnvironment sets up recipe packs for a single Radius.Core/environments resource. | ||
| // If the environment already has any recipe packs set (literal IDs or ARM expression references), | ||
| // no changes are made. Otherwise, it fetches or creates the default recipe pack from | ||
| // the default scope and injects their IDs into the template. | ||
| func (r *Runner) setupRecipePackForEnvironment(ctx context.Context, envResource map[string]any) error { | ||
| // The compiled ARM template has a double-nested properties structure: | ||
| // envResource["properties"]["properties"] is where resource-level fields live. | ||
| // Navigate to the inner (resource) properties map. | ||
| outerProps, ok := envResource["properties"].(map[string]any) | ||
| if !ok { | ||
| outerProps = map[string]any{} | ||
| envResource["properties"] = outerProps | ||
| } | ||
|
|
||
| properties, ok := outerProps["properties"].(map[string]any) | ||
| if !ok { | ||
| properties = map[string]any{} | ||
| outerProps["properties"] = properties | ||
| } | ||
|
|
||
| // If the environment already has any recipe packs configured (literal IDs or | ||
| // Bicep expression references), leave it as-is — the user is managing packs explicitly. | ||
| if hasAnyRecipePacks(properties) { | ||
| return nil | ||
| } | ||
|
Comment on lines
+690
to
+709
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about moving this as a property on https://github.com/kachawla/radius/blob/main/pkg/cli/bicep/resources.go#L38? Just provider better readability and abstraction. |
||
|
|
||
| // No recipe packs set — provide defaults from the default scope. | ||
|
|
||
| // Ensure the default resource group exists before accessing recipe packs. | ||
| mgmtClient, err := r.ConnectionFactory.CreateApplicationsManagementClient(ctx, *r.Workspace) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if err := recipepack.EnsureDefaultResourceGroup(ctx, mgmtClient.CreateOrUpdateResourceGroup); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Initialize the default scope client factory so we can access default recipe packs. | ||
| if r.DefaultScopeClientFactory == nil { | ||
| defaultFactory, err := cmd.InitializeRadiusCoreClientFactory(ctx, r.Workspace, recipepack.DefaultResourceGroupScope) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| r.DefaultScopeClientFactory = defaultFactory | ||
| } | ||
|
|
||
| recipePackDefaultClient := r.DefaultScopeClientFactory.NewRecipePacksClient() | ||
|
|
||
| // Try to GET the default recipe pack from the default scope. | ||
| // If it doesn't exist, create it. | ||
| packID, err := getOrCreateDefaultRecipePack(ctx, recipePackDefaultClient) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Inject the default recipe pack ID into the template. | ||
| properties["recipePacks"] = []any{packID} | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // hasAnyRecipePacks returns true if the environment properties have any recipe packs | ||
| // configured, including both literal string IDs and ARM expression references. | ||
| func hasAnyRecipePacks(properties map[string]any) bool { | ||
| recipePacks, ok := properties["recipePacks"] | ||
| if !ok { | ||
| return false | ||
| } | ||
| packsArray, ok := recipePacks.([]any) | ||
| if !ok { | ||
| return false | ||
| } | ||
| return len(packsArray) > 0 | ||
| } | ||
|
|
||
| // getOrCreateDefaultRecipePack attempts to GET the default recipe pack from | ||
| // the default scope. If it doesn't exist (404), it creates it with all core | ||
| // resource type recipes. Returns the full resource ID. | ||
| func getOrCreateDefaultRecipePack(ctx context.Context, client *v20250801preview.RecipePacksClient) (string, error) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we move recipe pack specific functionality like this to https://github.com/nithyatsu/radius/blob/e204475b2e5c24030995ac45fd9b4ce4f1441920/pkg/cli/recipepack/recipepack.go? |
||
| _, err := client.Get(ctx, recipepack.DefaultRecipePackResourceName, nil) | ||
| if err != nil { | ||
| if !clients.Is404Error(err) { | ||
| return "", fmt.Errorf("failed to get default recipe pack from default scope: %w", err) | ||
| } | ||
| // Not found — create the default recipe pack with all core types. | ||
| resource := recipepack.NewDefaultRecipePackResource() | ||
| _, err = client.CreateOrUpdate(ctx, recipepack.DefaultRecipePackResourceName, resource, nil) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to create default recipe pack: %w", err) | ||
| } | ||
| } | ||
| return recipepack.DefaultRecipePackID(), nil | ||
| } | ||
|
|
||
| // findRadiusCoreEnvironmentResources walks the template's resources and returns | ||
| // all Radius.Core/environments resources found (as mutable maps). | ||
| func findRadiusCoreEnvironmentResources(template map[string]any) []map[string]any { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have an existing function for this https://github.com/kachawla/radius/blob/main/pkg/cli/bicep/resources.go#L107 |
||
| if template == nil { | ||
| return nil | ||
| } | ||
|
|
||
| resourcesValue, ok := template["resources"] | ||
| if !ok { | ||
| return nil | ||
| } | ||
|
|
||
| resourcesMap, ok := resourcesValue.(map[string]any) | ||
| if !ok { | ||
| return nil | ||
| } | ||
|
|
||
| var envResources []map[string]any | ||
| for _, resourceValue := range resourcesMap { | ||
| resource, ok := resourceValue.(map[string]any) | ||
| if !ok { | ||
| continue | ||
| } | ||
|
|
||
| resourceType, ok := resource["type"].(string) | ||
| if !ok { | ||
| continue | ||
| } | ||
|
|
||
| if strings.HasPrefix(strings.ToLower(resourceType), "radius.core/environments") { | ||
| envResources = append(envResources, resource) | ||
| } | ||
| } | ||
|
|
||
| return envResources | ||
| } | ||
|
|
||
| // configureProviders configures environment and cloud providers based on the environment and provider type | ||
| func (r *Runner) configureProviders() error { | ||
| var env any | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we only expect one default recipe pack, right?