From 4e98b55d4355f3765e606d2d0f6cc27d4fbb5c6d Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Thu, 28 Aug 2025 12:21:55 -0700 Subject: [PATCH 01/24] draft recipe-pack design Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 296 +++++++++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 recipe/2025-08-recipe-packs.md diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md new file mode 100644 index 00000000..103cb904 --- /dev/null +++ b/recipe/2025-08-recipe-packs.md @@ -0,0 +1,296 @@ +# Recipe Packs + +* **Author**: `Nithya (@nithyatsu)` + +## Overview + +Recipes are external infrastructure-as-code (IaC) templates that operators register on a Radius Environment so developers can use them later for provisioning. They provide a mechanism for separation of concerns between developers and operators. + +Today, Radius supports registering recipes individually, either via the Environment resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Putting everything together manually this way each time can be error prone. + +This document details the introduction of Recipe Packs as a feature that makes recipe management easier. Recipe Packs are a collection of related recipes that a platform engineer can manage as a single entity. + +## Terms and definitions + +| Term | Definition | +| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Registry | A specific protocol and versioned hosting system for Terraform modules. Has an official public registry service as well as private services as part of Terraform cloud. Scant open-source implementations. | +| Recipe | IaC templates that operators register on a Radius Environment | +|Recipe Pack| A collection of recipes that can be managed as an entity | + +## Objectives + +> **Issue Reference:** + +### Goals + +Provide Recipe Packs as a Radius feature to bundle related recipes for easier management and sharing (e.g., a pack for ACI that includes all necessary recipes). + +### Non goals + +* Recipe Packs would bundle together Recipes, as we understand them today. We do not cover recipe versioning / other recipe specific enhancements in this design. + + +### User scenarios (optional) + +#### Registering several recipes to an environment + +As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. This can be error prone when there are many recipes. Radius should provide a way to bulk register( and manage) recipes. + +#### Registering recipes to multiple environment + +As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. Some of my developers use ACI computes while others use Kubernetes. But they all use same networking resources. Today, I have to create 2 Radius environment and manually link the recipe for compute, data. and networking for each of these teams, since they need different computes. Or I can create one dev environment and have named recipes, so that each team can see a compute recipe they dont use along with the one they use. I would like to be able to better organize recipes so that I can group them together independent of the environment, and reuse them across environment when suitable. In my above situation, I could register the same data, networking recipe-packs across environments and only link a different compute pack. + +## Design + +### Design details + +We model Recipe Pack as a first class Radius resource. + +Pros: + +- Helps manage the size of environment resource +- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource +- As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independant of environments. + +[Question]: would environment and recipe pack ever have different rbac? + +Cons: + +- This approach is a deviation from the current tooling approach for recipes. + + + +### Schema + +A sample recipe pack resource looks like below: + +``` +resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { + name: 'computeRecipePack' + description: "Recipe Pack for deploying to Kubernetes." + properties: { + recipes: [ + Radius.Compute/container: { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' + parameters: { + allowPlatformOptions: true + } + } + Radius.Security/secrets: { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' + } + Radius.Storage/volumes: { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' + } + ] + } +} +``` + +The schema for the type would look like: + +```yaml + + +``` + + +### API design (if applicable) + +We should support CRUDL operations on recipe-pack resource. This should be fairly automatic since recipe packs would be registered as an RRT. Once we register the schema for `Radius.Core/recipePacks` resource type using `rad resource-type create`, Dynamic RP should be able to dynamically look up the schema and perfom these operations. + + +### Server Side changes + + + + +### CLI design + +We should introduce rad cli commands to help manage recipe-packs. +We should add documentation to rad recipe commands indicating their future deprecation plan. + +1. Creating a recipe-pack should work once we create and register the recipe pack schema. + +``` +computeRecipePack.bicep: + +resource computeRecipePack 'Radius.Core/recipePacks@2025-05-01-preview' = { + name: 'computeRecipePack' + description: "Recipe Pack for deploying to Kubernetes." + properties: { + recipes: [ + Radius.Compute/container: { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' + parameters: { + allowPlatformOptions: true + } + } + Radius.Security/secrets: { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' + } + Radius.Storage/volumes: { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' + } + ] + } +} + +rad deploy computeRecipePack.bicep +``` + +2. +``` +$ rad recipe-pack show computeRecipePack + +RESOURCE TYPE GROUP STATE +computeRecipePack Radius.Core/recipePacks default Succeeded + +RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION +Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 +Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 +Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 + +``` + +3. +``` +$ rad recipe-pack list [optionally -e myenv] + +RESOURCE TYPE GROUP STATE +computeRecipePack Radius.Core/recipePacks default Succeeded +dataRecipePack. Radius.Core/recipePacks default Succeeded + +``` + +4. rad recipe-pack delete + +We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. + +5. rad env show should be updated + +Based on whether the environment namepsace is Applications.Core or Radius.Core, the outputs differ. + +``` +$ rad environment show my-env +RESOURCE TYPE GROUP STATE +my-env Radius.Core/environments default Succeeded + +RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION +computeRecipePack Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 +computeRecipePack Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 +computeRecipePack Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 +dataRecipePack Radius.Data/redisCaches terraform https://github.com/project-radius/resource-types-contrib.git//recipes/data/redisCaches?ref=v0.48 +``` + +``` +$ rad recipe list -environment my-env +RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION +computeRecipePack Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 +computeRecipePack Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 +computeRecipePack Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 +dataRecipePack Radius.Data/redisCaches terraform https://github.com/project-radius/resource-types-contrib.git//recipes/data/redisCaches?ref=v0.48 +networkingRecipePack Radius.Compute/gateways terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/gateways?ref=v0.48 +``` + + +### Breaking changes + +* Once we support recipe packs, the Radius.Core environments will allow only regitration of recipe-packs and not a single recipe. Applications.Core environments will continue to work as it does today and support recipe registeration but will be deprecated over time allowing transition time for customers move from recipes to recipe packs. + +* We will drop the support for named recipe - a way to register multiple recipes for the same resource-type in a single environment. + + +## Alternatives considered + +Below options were considered as alternatives to modeling recipe pack as a first class RRT - + +1. embed all recipe mappings inline in the Environment + +This is similar to what we have today. We could introduce a yaml spec similar to below, and when user executes a `rad recipe-pack register` this spec could be parsed and all recipes added to environment. + +```yaml +name: aci-production-pack +version: 1.0.0 +description: "Recipe Pack for deploying to ACI in production." +recipes: + - resourceType: "Radius.Compute/containers@2025-05-01-preview" + recipeKind: "bicep" + recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-container:1.2.0" + parameters: + cpu: "1.0" + memoryInGB: "2.0" + environmentVariables: + LOG_LEVEL: "Information" + # Optional: allow platform-specific options like containerGroupProfile for ACI + allowPlatformOptions: true + - resourceType: "Radius.Compute/gateways@2025-05-01-preview" + recipeKind: "bicep" + recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-gateway:1.1.0" + parameters: + sku: "Standard_v2" + - resourceType: "Radius.Security/secrets@2025-05-01-preview" + recipeKind: "bicep" + recipeLocation: "oci://ghcr.io/my-org/recipes/azure/keyvault-secretstore:1.0.0" + parameters: + skuName: "premium" +``` + +Pros: + +- Most compatible to what we have in Radius today and hence the fastest approach. +- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the yaml manifest + + +Cons: + +- Environment still stays a bloated object. Environment resource houses a lot of other properties and we could potentially risk hiting the mechanical limits that apply to serializing objects. + +- a list of recipes could potentially be managed as a collection, including having its own rbac and appearance in app graph. The above approach does not allow for that possibility. + +2. store a URL to a YAML manifest in the Environment + +We could fetch the yaml when needed, and use the available recipe. + +`rad environment update my-env --recipe-packs aci-production-pack='git::https://github.com/my-org/recipe-packs.git//aci-production-pack.yaml?ref=1.0.0'` + +Pros: + +- Helps manage the size of environment resource +- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the yaml manifest + +Cons: + +- For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could cache the list and construct an im-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. + +## Test plan + + + +## Security + + + +## Compatibility (optional) + + +## Monitoring + +No changes needed + +## Development plan + + + + +## Open issues + + + From df836e0857aa5d143764430517d67077221d478f Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Thu, 28 Aug 2025 15:56:27 -0700 Subject: [PATCH 02/24] add schema Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 70 +++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 103cb904..ceb03c34 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -6,7 +6,7 @@ Recipes are external infrastructure-as-code (IaC) templates that operators register on a Radius Environment so developers can use them later for provisioning. They provide a mechanism for separation of concerns between developers and operators. -Today, Radius supports registering recipes individually, either via the Environment resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Putting everything together manually this way each time can be error prone. +Today, Radius supports registering recipes individually, either via the Environment resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Putting everything together manually this way for each environment is error prone. Recipes also do not have a lifecycle of their own and can be managed only by managing the environments pointing to them. This document details the introduction of Recipe Packs as a feature that makes recipe management easier. Recipe Packs are a collection of related recipes that a platform engineer can manage as a single entity. @@ -14,7 +14,6 @@ This document details the introduction of Recipe Packs as a feature that makes r | Term | Definition | | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Registry | A specific protocol and versioned hosting system for Terraform modules. Has an official public registry service as well as private services as part of Terraform cloud. Scant open-source implementations. | | Recipe | IaC templates that operators register on a Radius Environment | |Recipe Pack| A collection of recipes that can be managed as an entity | @@ -28,7 +27,7 @@ Provide Recipe Packs as a Radius feature to bundle related recipes for easier ma ### Non goals -* Recipe Packs would bundle together Recipes, as we understand them today. We do not cover recipe versioning / other recipe specific enhancements in this design. +Recipe Packs would bundle together Recipes, as we understand them today. We do not cover recipe versioning / other recipe specific enhancements in this design. ### User scenarios (optional) @@ -49,9 +48,9 @@ We model Recipe Pack as a first class Radius resource. Pros: -- Helps manage the size of environment resource - Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource - As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independant of environments. +- Helps manage the size of environment resource [Question]: would environment and recipe pack ever have different rbac? @@ -70,7 +69,7 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { name: 'computeRecipePack' description: "Recipe Pack for deploying to Kubernetes." properties: { - recipes: [ + recipes: { Radius.Compute/container: { recipeKind: 'terraform' recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' @@ -86,7 +85,7 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { recipeKind: 'terraform' recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' } - ] + } } } ``` @@ -94,10 +93,63 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { The schema for the type would look like: ```yaml - - +namespace: Radius.Core + types: + recipePacks: + description: Recipe Pack for grouping and managing related recipes + apiVersions: + '2026-01-01-preview': + schema: + type: object + properties: + name: + type: string + description: The name of the recipe pack + description: + type: string + description: Description of what this recipe pack provides + recipes: + type: object + description: Map of resource types to their recipe configurations + additionalProperties: + type: object + properties: + recipeKind: + type: string + description: The type of recipe (e.g., terraform, bicep) + enum: + - terraform + - bicep + recipeLocation: + type: string + description: URL or path to the recipe source + parameters: + type: object + description: Parameters to pass to the recipe + additionalProperties: + type: string + required: + - recipeKind + - recipeLocation + required: + - name + - recipes ``` +// Question: The recipe collection should be curly braces, is that OK (feature spec has []) ? OR we keep it array like below. Map could make it easier to look up using resource type. + +"recipes": [ + { + "resourceType": "Radius.Compute/containers", + "recipeKind": "terraform", + "recipeLocation": "https://example.com/recipes/containers.zip" + }, + { + "resourceType": "Radius.Storage/volumes", + "recipeKind": "terraform", + "recipeLocation": "https://example.com/recipes/volumes.zip" + } + ] ### API design (if applicable) @@ -108,7 +160,6 @@ We should support CRUDL operations on recipe-pack resource. This should be fairl - ### CLI design We should introduce rad cli commands to help manage recipe-packs. @@ -283,7 +334,6 @@ Cons: ## Monitoring -No changes needed ## Development plan From 645bff389796a515dd3bc401681ee30baed1cade Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Tue, 2 Sep 2025 08:58:33 -0700 Subject: [PATCH 03/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index ceb03c34..fcde7350 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -16,6 +16,7 @@ This document details the introduction of Recipe Packs as a feature that makes r | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Recipe | IaC templates that operators register on a Radius Environment | |Recipe Pack| A collection of recipes that can be managed as an entity | +|RRT| [Radius Resource Type](https://docs.radapp.io/guides/author-apps/custom/overview/)| ## Objectives @@ -23,7 +24,7 @@ This document details the introduction of Recipe Packs as a feature that makes r ### Goals -Provide Recipe Packs as a Radius feature to bundle related recipes for easier management and sharing (e.g., a pack for ACI that includes all necessary recipes). +Provide Recipe Packs as a Radius feature to bundle and import (register) multiple recipes into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). ### Non goals @@ -44,7 +45,7 @@ As an operator I am responsible for creating Radius Environments using which dev ### Design details -We model Recipe Pack as a first class Radius resource. +We model Recipe Pack as a first class RRT. Pros: @@ -127,7 +128,7 @@ namespace: Radius.Core type: object description: Parameters to pass to the recipe additionalProperties: - type: string + type: any required: - recipeKind - recipeLocation @@ -136,6 +137,8 @@ namespace: Radius.Core - recipes ``` +Today the RRT schema does not allow `any` as a type for security reasons. We would have to remove that constraint in bicep tooling so that we can have the recipe parameters as defined above. + // Question: The recipe collection should be curly braces, is that OK (feature spec has []) ? OR we keep it array like below. Map could make it easier to look up using resource type. "recipes": [ @@ -304,9 +307,12 @@ Cons: - Environment still stays a bloated object. Environment resource houses a lot of other properties and we could potentially risk hiting the mechanical limits that apply to serializing objects. +- Add Radius commands to publish recipe-packs, similar to what we have for recipes today. + - a list of recipes could potentially be managed as a collection, including having its own rbac and appearance in app graph. The above approach does not allow for that possibility. -2. store a URL to a YAML manifest in the Environment + +1. store a URL to a YAML manifest in the Environment We could fetch the yaml when needed, and use the available recipe. @@ -343,4 +349,17 @@ Cons: ## Open issues +## notes/questions for myself (TBD) + +recipe-pack : RRT or NOT? same question as RRT in the Radius.Config namespace (app, env). These types are not meant to be edited by users, and should be as defined by Radius so that Radius can work. + +- rad init today says instaling a "recipe-pack" - might need changes here to enable choosing a pack. +- rad init / install must be updated to create the recipe pack resource type ( as part of registering manifests logic we have today) +- if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. +- we are moving away from named recipes. If a customer wishes to use same env for two applications, these application teams have their own recipes, then would we advice them to create 2 enviroments ? We could also guide them to a naming like contoso-recipe-pack and cool-prod-recipe-pack. But this would either require us to allow for duplicate recipes between packs, or require multiple teams to coordinate and ensure their types are different? +- now that the "unit" of importing recipes is recipe pack, would we "contrib" recipe pack manifests? +- would we think about enforcing a size limit on recipe pack? how many recipes it can have ? + + + From a70e14b0bd01f07de1c54f2a6696324137b37b6c Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 3 Sep 2025 08:40:30 -0700 Subject: [PATCH 04/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 38 ++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index fcde7350..1bc52cec 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -6,7 +6,7 @@ Recipes are external infrastructure-as-code (IaC) templates that operators register on a Radius Environment so developers can use them later for provisioning. They provide a mechanism for separation of concerns between developers and operators. -Today, Radius supports registering recipes individually, either via the Environment resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Putting everything together manually this way for each environment is error prone. Recipes also do not have a lifecycle of their own and can be managed only by managing the environments pointing to them. +Today, Radius supports registering recipes individually, either via the `Applications.Core\environments` resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Some customers could have 1000s of environments and putting everything together manually for each environment is error prone. Recipes also do not have a lifecycle of their own and can be managed only by managing the environments pointing to them. This document details the introduction of Recipe Packs as a feature that makes recipe management easier. Recipe Packs are a collection of related recipes that a platform engineer can manage as a single entity. @@ -15,8 +15,8 @@ This document details the introduction of Recipe Packs as a feature that makes r | Term | Definition | | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Recipe | IaC templates that operators register on a Radius Environment | -|Recipe Pack| A collection of recipes that can be managed as an entity | -|RRT| [Radius Resource Type](https://docs.radapp.io/guides/author-apps/custom/overview/)| +| Recipe Pack| A collection of recipes that can be managed as an entity | +| RRT | [Radius Resource Type](https://docs.radapp.io/guides/author-apps/custom/overview/)| ## Objectives @@ -24,7 +24,7 @@ This document details the introduction of Recipe Packs as a feature that makes r ### Goals -Provide Recipe Packs as a Radius feature to bundle and import (register) multiple recipes into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). +Provide Recipe Packs as a Radius feature to bundle multiple recipes as a single managable entity into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). ### Non goals @@ -35,35 +35,46 @@ Recipe Packs would bundle together Recipes, as we understand them today. We do n #### Registering several recipes to an environment -As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. This can be error prone when there are many recipes. Radius should provide a way to bulk register( and manage) recipes. +As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. This can be error prone when there are many recipes and environments. Radius should provide a way to bulk register( and manage) recipes. #### Registering recipes to multiple environment -As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. Some of my developers use ACI computes while others use Kubernetes. But they all use same networking resources. Today, I have to create 2 Radius environment and manually link the recipe for compute, data. and networking for each of these teams, since they need different computes. Or I can create one dev environment and have named recipes, so that each team can see a compute recipe they dont use along with the one they use. I would like to be able to better organize recipes so that I can group them together independent of the environment, and reuse them across environment when suitable. In my above situation, I could register the same data, networking recipe-packs across environments and only link a different compute pack. +As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. I having 100s of environment which mostly use the same recipes. Piecing the same recipes together for each environment feels like rework. ## Design -### Design details +### Design Overview -We model Recipe Pack as a first class RRT. +We choose modelling Recipe Pack as a first class Radius Resource Type. [Alternatives considered](#alternatives-considered) section details some other possibilities. Pros: - Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource - As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independant of environments. -- Helps manage the size of environment resource +- Helps reduce the size of environment resource, which could reach serization limits with tons of recipes. +- Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. [Question]: would environment and recipe pack ever have different rbac? Cons: - This approach is a deviation from the current tooling approach for recipes. +- While this brings in many advantages, RRTs can have their schema modified using rad resource-type commands. We should find ways to prevent this from happening. In general, Radius.Core namespace would have resources whose schema should be non-editable so that Radius can work as expected. Some other resources that would fall in this category are environments and applications. +At a high level, this design approach needs the below steps +* Design schema for Radius.Core/recipePacks type +* Register the resultant schema manifest as part of Radius start up sequence +* Support `rad cli` commands that enable CRUDL operations on resources of type Radius.Core/recipePacks +* Design Radius.Core/environment schema +* Register the schema as part of Radius start up sequence +* Support `rad cli` commands that enable managing Radius.Core/environment resources through CRUDL operations on this type of resource +* Support `rad cli` commands that enable registering recipe-packs to a `Radius.Core\environments` environment resource +* Enhance Dynamic RP to look through the set of registered recipe-packs in the active environment, fetch the recipe-pack resources and then fetch the link of recipe for resource provisioning -### Schema +### -A sample recipe pack resource looks like below: +A sample recipe pack resource would look like below: ``` resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { @@ -75,7 +86,8 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { recipeKind: 'terraform' recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' parameters: { - allowPlatformOptions: true + allowPlatformOptions: true + anIntegerParam : 1 } } Radius.Security/secrets: { @@ -137,7 +149,7 @@ namespace: Radius.Core - recipes ``` -Today the RRT schema does not allow `any` as a type for security reasons. We would have to remove that constraint in bicep tooling so that we can have the recipe parameters as defined above. +Today the RRT schema does not allow `any` as a type for security reasons. We would have to remove that constraint in bicep tooling and radius so that we can have the recipe parameters as defined above. // Question: The recipe collection should be curly braces, is that OK (feature spec has []) ? OR we keep it array like below. Map could make it easier to look up using resource type. From 711d1ce2b4130b54a14308e2a948cc0b614a1f8c Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 3 Sep 2025 14:01:17 -0700 Subject: [PATCH 05/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 1bc52cec..2c843d85 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -363,14 +363,16 @@ Cons: ## notes/questions for myself (TBD) -recipe-pack : RRT or NOT? same question as RRT in the Radius.Config namespace (app, env). These types are not meant to be edited by users, and should be as defined by Radius so that Radius can work. - +- recipe-pack : RRT or NOT? same question as RRT in the Radius.Config namespace (app, env). These types are not meant to be edited by users, and should be as defined by Radius so that Radius can work. - rad init today says instaling a "recipe-pack" - might need changes here to enable choosing a pack. - rad init / install must be updated to create the recipe pack resource type ( as part of registering manifests logic we have today) - if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. +- handling recipe-packs with dup recipes. at the time of creation, of recipe pack, it could have dups with another erescipe-pack. But we have to dtect dups at the time of registering to env. - we are moving away from named recipes. If a customer wishes to use same env for two applications, these application teams have their own recipes, then would we advice them to create 2 enviroments ? We could also guide them to a naming like contoso-recipe-pack and cool-prod-recipe-pack. But this would either require us to allow for duplicate recipes between packs, or require multiple teams to coordinate and ensure their types are different? - now that the "unit" of importing recipes is recipe pack, would we "contrib" recipe pack manifests? - would we think about enforcing a size limit on recipe pack? how many recipes it can have ? +- - should recipe-pack resource have a list of env ids to which it belongs? typically, RRTs have an app id or env id. +- - cli -support versus deploying through bicep From 44fb67bc3836c656df3b8517c138d1e185e5ad2a Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Tue, 9 Sep 2025 21:23:45 -0700 Subject: [PATCH 06/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 257 ++++++++++++++++++++++----------- 1 file changed, 172 insertions(+), 85 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 2c843d85..76426e07 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -8,7 +8,7 @@ Recipes are external infrastructure-as-code (IaC) templates that operators regis Today, Radius supports registering recipes individually, either via the `Applications.Core\environments` resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Some customers could have 1000s of environments and putting everything together manually for each environment is error prone. Recipes also do not have a lifecycle of their own and can be managed only by managing the environments pointing to them. -This document details the introduction of Recipe Packs as a feature that makes recipe management easier. Recipe Packs are a collection of related recipes that a platform engineer can manage as a single entity. +This document proposes the design of a Recipe Pack as an first class resource type in Radius. The Recipe Pack enables bundling multiple recipe selections for different resource types into a reusable unit that can be referenced by environments. ## Terms and definitions @@ -24,11 +24,13 @@ This document details the introduction of Recipe Packs as a feature that makes r ### Goals -Provide Recipe Packs as a Radius feature to bundle multiple recipes as a single managable entity into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). +Provide Recipe Packs as a Radius feature to bundle multiple recipes as a single manageable entity into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). + +- Radius should provide APIs to manage Radius.Core/recipePacks resource through CRUDL operations ### Non goals -Recipe Packs would bundle together Recipes, as we understand them today. We do not cover recipe versioning / other recipe specific enhancements in this design. +Recipe Packs would bundle together "recipes" as we understand them today. We do not cover recipe versioning / other recipe specific enhancements in this design. ### User scenarios (optional) @@ -45,36 +47,141 @@ As an operator I am responsible for creating Radius Environments using which dev ### Design Overview -We choose modelling Recipe Pack as a first class Radius Resource Type. [Alternatives considered](#alternatives-considered) section details some other possibilities. +We choose modeling recipe packs as a first class Radius resource of type +Radius.Core/recipePacks provisioned imperatively by Applications RP . [Alternatives considered](#alternatives-considered) section details some other options we considered. Pros: - Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource -- As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independant of environments. -- Helps reduce the size of environment resource, which could reach serization limits with tons of recipes. +- As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and RBAC independent of environments. +- Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. - Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. +- Imperative provisioning prevents users from accidentally experimenting with the resource schema -[Question]: would environment and recipe pack ever have different rbac? Cons: - This approach is a deviation from the current tooling approach for recipes. -- While this brings in many advantages, RRTs can have their schema modified using rad resource-type commands. We should find ways to prevent this from happening. In general, Radius.Core namespace would have resources whose schema should be non-editable so that Radius can work as expected. Some other resources that would fall in this category are environments and applications. +- Supporting recipe packs as a Applications RP type requires manual implementation of schema and API in contrast to modeling it as a dynamic resources. -At a high level, this design approach needs the below steps +At a very high level, this design approach needs the below steps -* Design schema for Radius.Core/recipePacks type -* Register the resultant schema manifest as part of Radius start up sequence +* Add support for Radius.Core/recipePacks resource in Applications RP + * Schema + API design and implementation * Support `rad cli` commands that enable CRUDL operations on resources of type Radius.Core/recipePacks -* Design Radius.Core/environment schema -* Register the schema as part of Radius start up sequence +* Design and support Radius.Core/environment schema in Applications RP * Support `rad cli` commands that enable managing Radius.Core/environment resources through CRUDL operations on this type of resource * Support `rad cli` commands that enable registering recipe-packs to a `Radius.Core\environments` environment resource -* Enhance Dynamic RP to look through the set of registered recipe-packs in the active environment, fetch the recipe-pack resources and then fetch the link of recipe for resource provisioning +* Enhance Dynamic RP, Applications RP and UCP to support the feature. + +### Schema and API design + +As part of supporting Recipe Pack as a resource type, at a high-level, +We define a recipePacks.tsp (Note we currently do not have a Radius.Core namespace and we have to make code changes to set this namespace up with at-least environments and recipePacks) + +```tsp +namespace Radius.Core; + +@doc("The recipe pack resource") +model RecipePackResource + is TrackedResourceRequired { + @doc("recipe pack name") + @key("recipePackName") + @path + @segment("recipePacks") + name: ResourceNameString; +} + +@doc("Recipe Pack properties") +model RecipePackProperties { + @doc("The status of the asynchronous operation.") + @visibility("read") + provisioningState?: ProvisioningState; + + @doc("Description of what this recipe pack provides") + description?: string; + + @doc("Map of resource types to their recipe configurations") + recipes: Record; +} + +@doc("Recipe definition for a specific resource type") +model RecipeDefinition { + @doc("The type of recipe (e.g., terraform, bicep)") + recipeKind: RecipeKind; + + @doc("URL or path to the recipe source") + recipeLocation: string; + + @doc("Parameters to pass to the recipe") + parameters?: {}; +} + +@doc("The type of recipe") +enum RecipeKind { + @doc("Terraform recipe") + terraform: "terraform", + + @doc("Bicep recipe") + bicep: "bicep", +} + + +@armResourceOperations +interface RecipePacks { + get is ArmResourceRead< + RecipePackResource, + UCPBaseParameters + >; + + createOrUpdate is ArmResourceCreateOrReplaceSync< + RecipePackResource, + UCPBaseParameters + >; + + update is ArmResourcePatchSync< + RecipePackResource, + RecipePackProperties, + UCPBaseParameters + >; + + delete is ArmResourceDeleteSync< + RecipePackResource, + UCPBaseParameters + >; + + listByScope is ArmResourceListByParent< + RecipePackResource, + UCPBaseParameters, + "Scope", + "Scope" + >; +} +``` + +* We choose map of resource types to their recipe configurations so that the relevant recipe can be easily accessed. +* We will not be supporting named recipes going forward as documented in [RRT feature spec](https://github.com/willtsai/design-notes-radius/blob/f9c98baf515263c27e7637131d7a48ae5a01b2c0/features/2025-02-user-defined-resource-type-feature-spec.md#user-story-7--registering-recipes). Therefore the `RecipeDefinition` model does not include a name. +* The operations are all Synchronous, since Recipe Pack a light weight configuration resource. +* createOrUpdate returns a `HTTP 201 Created` when recipe pack creation is successful and `HTTP 200 OK` for successful updates, with json payload representing the recipe pack resource created. + + +[Sample to be added] + +* get returns `HTTP 200 OK` + payload of the serialized recipe pack resource that corresponds to the resource ID. + +[Sample to be added] + +* delete returns `HTTP 200 OK` upon successful deletion of recipe pack resource that corresponds to the resource ID. Other possible response is `HTTP 404 Not Found`. + +[Sample to be added] -### +* listByScope returns `HTTP 200 OK` with payload containing a list of recipe packs in the given scope. -A sample recipe pack resource would look like below: +[Sample to be added] + +#### Example + +Below is a sample bicep definition of a recipe pack resource - ``` resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { @@ -103,76 +210,33 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { } ``` -The schema for the type would look like: - -```yaml -namespace: Radius.Core - types: - recipePacks: - description: Recipe Pack for grouping and managing related recipes - apiVersions: - '2026-01-01-preview': - schema: - type: object - properties: - name: - type: string - description: The name of the recipe pack - description: - type: string - description: Description of what this recipe pack provides - recipes: - type: object - description: Map of resource types to their recipe configurations - additionalProperties: - type: object - properties: - recipeKind: - type: string - description: The type of recipe (e.g., terraform, bicep) - enum: - - terraform - - bicep - recipeLocation: - type: string - description: URL or path to the recipe source - parameters: - type: object - description: Parameters to pass to the recipe - additionalProperties: - type: any - required: - - recipeKind - - recipeLocation - required: - - name - - recipes -``` - -Today the RRT schema does not allow `any` as a type for security reasons. We would have to remove that constraint in bicep tooling and radius so that we can have the recipe parameters as defined above. - -// Question: The recipe collection should be curly braces, is that OK (feature spec has []) ? OR we keep it array like below. Map could make it easier to look up using resource type. - -"recipes": [ - { - "resourceType": "Radius.Compute/containers", - "recipeKind": "terraform", - "recipeLocation": "https://example.com/recipes/containers.zip" - }, - { - "resourceType": "Radius.Storage/volumes", - "recipeKind": "terraform", - "recipeLocation": "https://example.com/recipes/volumes.zip" - } - ] +### Server Side changes -### API design (if applicable) +At a high level, below changes are necessary - -We should support CRUDL operations on recipe-pack resource. This should be fairly automatic since recipe packs would be registered as an RRT. Once we register the schema for `Radius.Core/recipePacks` resource type using `rad resource-type create`, Dynamic RP should be able to dynamically look up the schema and perfom these operations. +1. Add support to UCP to route `Radius.Core\recipePacks` resource operations to Applications RP. +2. In Applications RP + 1. Add schema / swagger changes to support the `Radius.Core\recipePacks` resource type + 2. Add convertors for handling conversions from and to version agnostic data model. + 3. Add backend/controller support for creating/updating/listing/deleting the resource. Constraints for each operation are detailed later in [Recipe Pack Operations](#schema-and-api-design) + 4. Finalize the `Radius.Core\environments` details and then + 5. Add schema / swagger changes to support the `Radius.Core\environments` resource type + 6. Add convertors for handling conversions from and to version agnostic data model. + 7. Add backend/controller support for creating/updating/deleting the resource. + 8. Add support to look up the `Radius.Core\environments` that is in use + 9. Since we cannot register multiple recipe-packs that have recipe for same resource type, Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. + 10. Use the recipe information just fetched and reuse the existing recipe engine mechanism. +3. In Dynamic RP, while deploying a dynamic resource + 1. Add support to look up the `Radius.Core\environments` that is in use + 2. Since we cannot register multiple recipe-packs that have recipe for same resource type, Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. + 3. Use the recipe information just fetched and reuse the existing recipe engine mechanism. +4. No changes to controller or DE. -### Server Side changes +Some of the design decisions we have are: +* Recipes cannot registered to Radius.Core\environments. As a consequence, the users have to create a recipe-pack even when there is just one recipe to be registered. +* Recipe Packs cannot be registered to Applications.Core\environments. This is because Applications.Core\environments will be eventually deprecated in favor of Radius.Core/environments. ### CLI design @@ -212,7 +276,9 @@ resource computeRecipePack 'Radius.Core/recipePacks@2025-05-01-preview' = { rad deploy computeRecipePack.bicep ``` -2. +Note: rad recipe-pack create command could be added in future. For now, we are using rad deploy to create recipe packs. + +1. ``` $ rad recipe-pack show computeRecipePack @@ -236,13 +302,17 @@ dataRecipePack. Radius.Core/recipePacks default Succeeded ``` +If no -e is specified, this command should list all recipe packs in current scope. + 4. rad recipe-pack delete We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. +5. rad env register recipe-pack recipe-pack-name [-g group id] + 5. rad env show should be updated -Based on whether the environment namepsace is Applications.Core or Radius.Core, the outputs differ. +Based on whether the environment namespace is Applications.Core or Radius.Core, the outputs differ. Eventually Applications.Core support will be removed. ``` $ rad environment show my-env @@ -269,7 +339,7 @@ networkingRecipePack Radius.Compute/gateways terraform ### Breaking changes -* Once we support recipe packs, the Radius.Core environments will allow only regitration of recipe-packs and not a single recipe. Applications.Core environments will continue to work as it does today and support recipe registeration but will be deprecated over time allowing transition time for customers move from recipes to recipe packs. +* Once we support recipe packs, the Radius.Core environments will allow only registration of recipe-packs and not a single recipe. Applications.Core environments will continue to work as it does today and support recipe registration but will be deprecated over time allowing transition time for customers move from recipes to recipe packs. * We will drop the support for named recipe - a way to register multiple recipes for the same resource-type in a single environment. @@ -339,6 +409,21 @@ Cons: - For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could cache the list and construct an im-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. +1. model recipe packs as Radius Resource type provided by Dynamic RP. + +Pros: + +- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource +- As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independent of environments. +- Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. +- Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. + +Cons: + +- While this brings in just as many advantages as the chosen design approach, RRTs can have their schema modified using rad resource-type commands. We would have to find ways to prevent this from happening. + +In general, Radius.Core namespace has resources whose schema should be non-editable so that Radius can work as expected, for example Applications, Environments and recipePacks. These resources must be provisioned imperatively by Applications RP. + ## Test plan @@ -367,7 +452,9 @@ Cons: - rad init today says instaling a "recipe-pack" - might need changes here to enable choosing a pack. - rad init / install must be updated to create the recipe pack resource type ( as part of registering manifests logic we have today) - if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. -- handling recipe-packs with dup recipes. at the time of creation, of recipe pack, it could have dups with another erescipe-pack. But we have to dtect dups at the time of registering to env. +- would environment and recipe pack ever have different rbac? should we "allow" recipepack is in different radius resource grpup from that of environment? +- - prereq: finalize new environment design +- handling recipe-packs with dup recipes. at the time of creation, of recipe pack, it could have dups with another recipe-pack. But we have to dtect dups at the time of registering to env. - we are moving away from named recipes. If a customer wishes to use same env for two applications, these application teams have their own recipes, then would we advice them to create 2 enviroments ? We could also guide them to a naming like contoso-recipe-pack and cool-prod-recipe-pack. But this would either require us to allow for duplicate recipes between packs, or require multiple teams to coordinate and ensure their types are different? - now that the "unit" of importing recipes is recipe pack, would we "contrib" recipe pack manifests? - would we think about enforcing a size limit on recipe pack? how many recipes it can have ? From 37b48a38e7076ec7d51c26f885c336a27358cdb7 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 10 Sep 2025 10:29:25 -0700 Subject: [PATCH 07/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 123 ++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 25 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 76426e07..945f9b7e 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -162,9 +162,10 @@ interface RecipePacks { * We choose map of resource types to their recipe configurations so that the relevant recipe can be easily accessed. * We will not be supporting named recipes going forward as documented in [RRT feature spec](https://github.com/willtsai/design-notes-radius/blob/f9c98baf515263c27e7637131d7a48ae5a01b2c0/features/2025-02-user-defined-resource-type-feature-spec.md#user-story-7--registering-recipes). Therefore the `RecipeDefinition` model does not include a name. * The operations are all Synchronous, since Recipe Pack a light weight configuration resource. -* createOrUpdate returns a `HTTP 201 Created` when recipe pack creation is successful and `HTTP 200 OK` for successful updates, with json payload representing the recipe pack resource created. +* createOrUpdate returns a `HTTP 201 Created` when recipe pack creation is successful and `HTTP 200 OK` for successful updates, with json payload representing the recipe pack resource created. + [Sample to be added] * get returns `HTTP 200 OK` + payload of the serialized recipe pack resource that corresponds to the resource ID. @@ -214,29 +215,74 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { At a high level, below changes are necessary - -1. Add support to UCP to route `Radius.Core\recipePacks` resource operations to Applications RP. -2. In Applications RP - 1. Add schema / swagger changes to support the `Radius.Core\recipePacks` resource type - 2. Add convertors for handling conversions from and to version agnostic data model. - 3. Add backend/controller support for creating/updating/listing/deleting the resource. Constraints for each operation are detailed later in [Recipe Pack Operations](#schema-and-api-design) - 4. Finalize the `Radius.Core\environments` details and then - 5. Add schema / swagger changes to support the `Radius.Core\environments` resource type - 6. Add convertors for handling conversions from and to version agnostic data model. - 7. Add backend/controller support for creating/updating/deleting the resource. - 8. Add support to look up the `Radius.Core\environments` that is in use - 9. Since we cannot register multiple recipe-packs that have recipe for same resource type, Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. - 10. Use the recipe information just fetched and reuse the existing recipe engine mechanism. -3. In Dynamic RP, while deploying a dynamic resource - 1. Add support to look up the `Radius.Core\environments` that is in use - 2. Since we cannot register multiple recipe-packs that have recipe for same resource type, Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. - 3. Use the recipe information just fetched and reuse the existing recipe engine mechanism. -4. No changes to controller or DE. +#### UCP + + Add support to UCP to route `Radius.Core\recipePacks` resource operations to Applications RP in below section. (might need more changes) + +/radius/deploy/Chart/templates/ucp/configmaps.yaml + +```yaml +initialization: + planes: + - id: "/planes/radius/local" + properties: + resourceProviders: + Applications.Core: "http://applications-rp.radius-system:5443" + Applications.Dapr: "http://applications-rp.radius-system:5443" + Applications.Datastores: "http://applications-rp.radius-system:5443" + Applications.Messaging: "http://applications-rp.radius-system:5443" + Microsoft.Resources: "http://bicep-de.radius-system:6443" + kind: "UCPNative" +``` + +#### Applications RP + +There are two prerequisites for implementing recipe packs: + +1. Support new Radius.Core namespace. We would add Radius.Core namespace so that there is a transition time for users to move from Applications.Core/environments and recipes to Radius.Core/environment and Radius.Core/recipePacks. +Eventually Applications.Core will be deprecated and removed. + +2. Radius.Core/environments design and implementation. + +Below changes are needed for supporting recipe packs as new feature. + + 1. Add schema /swagger changes to support the `Radius.Core\recipePacks` resource type ([typepec changes](#schema-and-api-design)) + + 2. Create datamodel and convertors for handling recipe pack resource in /radius/pkg/corerp/api/v20231001preview/ and /radius/pkg/corerp/datamodel/ + + 3. Add controller support for creating/updating/listing/deleting the resource in `/radius/pkg/corerp/frontend/controller/`. Constraints for each operation are captured in [Recipe Pack Operations](#schema-and-api-design) + + 4. When an Applications RP supported resource is being deployed, the resource could be recipe based (portable) or non recipe based today (applications and environment). For recipe based resources, `/radius/pkg/portableresources/backend/controller/createorupdateresource.go` should be updated to + 1. fetch environment's recipe-pack ids + 2. get recipe-pack resource one at a time, stopping as soon as a match for resource-type is found. + 3. Then it should populate RecipeMetaData appropriately before calling the engine. + This flow should come in place if the environment used for deploying is of type Radius.Core/environments only. + +As part of Radius.Core/environments design/ implementation below points should be considered: -Some of the design decisions we have are: + 1. Finalize the `Radius.Core\environments` details and then -* Recipes cannot registered to Radius.Core\environments. As a consequence, the users have to create a recipe-pack even when there is just one recipe to be registered. -* Recipe Packs cannot be registered to Applications.Core\environments. This is because Applications.Core\environments will be eventually deprecated in favor of Radius.Core/environments. + 2. Add schema / swagger changes to support the `Radius.Core\environments` resource type + + 3. Add convertors for handling conversions from and to version agnostic data model. + + 4. Add backend/controller support for creating/updating/deleting the resource. + + 5. rad env register should support registering a recipe pack to Radius.Core/environments resource, and disallow recipes. + + + +#### Dynamic RP changes + +1. In Dynamic RP, while deploying a dynamic resource + 1. Add support to look up the `Radius.Core\environments` that is in use, fetch environment's recipe-pack ids + 2. Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. + 3. Use the recipe information just fetched and construct recipe details that can be passed to the existing recipe engine mechanism. + +#### Other components + +2. No changes to controller or DE. ### CLI design @@ -309,8 +355,9 @@ If no -e is specified, this command should list all recipe packs in current scop We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. 5. rad env register recipe-pack recipe-pack-name [-g group id] +We specify group resource id if the recipe-pack is in a different scope from the environment. -5. rad env show should be updated +6. rad env show should be updated Based on whether the environment namespace is Applications.Core or Radius.Core, the outputs differ. Eventually Applications.Core support will be removed. @@ -326,6 +373,7 @@ computeRecipePack Radius.Storage/volumes terraform dataRecipePack Radius.Data/redisCaches terraform https://github.com/project-radius/resource-types-contrib.git//recipes/data/redisCaches?ref=v0.48 ``` +7. rad recipe list ``` $ rad recipe list -environment my-env RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION @@ -336,6 +384,31 @@ dataRecipePack Radius.Data/redisCaches terraform networkingRecipePack Radius.Compute/gateways terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/gateways?ref=v0.48 ``` +8. rad init + +Today, rad init works as show below: + +``` +Initializing Radius. This may take a minute or two... + +🕒 Install Radius 7af38a9 + - Kubernetes cluster: kind-kin2 + - Kubernetes namespace: radius-system +⏳ Create new environment default + - Kubernetes namespace: default + - Recipe pack: local-dev +⏳ Scaffold application resource-types-contrib +⏳ Update local configuration +``` +The default environment created is initialized with a "recipe pack" which is a bunch of kubernetes recipes. + +We are choosing to keep the same behavior. But behind the scenes rad init would create. recipe pack resource, with recipe links we use today to construct recipe properties and add this recipe pack's resource id to the environment. + +Providing an option for az/ aws based recipe packs requires considerable work and would be a future follow up to the feature. + +### Graph support + +### Logging/ Tracing support ### Breaking changes @@ -390,7 +463,7 @@ Cons: - Environment still stays a bloated object. Environment resource houses a lot of other properties and we could potentially risk hiting the mechanical limits that apply to serializing objects. - Add Radius commands to publish recipe-packs, similar to what we have for recipes today. - + - a list of recipes could potentially be managed as a collection, including having its own rbac and appearance in app graph. The above approach does not allow for that possibility. @@ -446,10 +519,10 @@ In general, Radius.Core namespace has resources whose schema should be non-edita ## Open issues -## notes/questions for myself (TBD) +## notes/questions for myself (to be deleted) - recipe-pack : RRT or NOT? same question as RRT in the Radius.Config namespace (app, env). These types are not meant to be edited by users, and should be as defined by Radius so that Radius can work. -- rad init today says instaling a "recipe-pack" - might need changes here to enable choosing a pack. +- rad init today says installing a "recipe-pack" - might need changes here to enable choosing a pack. - rad init / install must be updated to create the recipe pack resource type ( as part of registering manifests logic we have today) - if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. - would environment and recipe pack ever have different rbac? should we "allow" recipepack is in different radius resource grpup from that of environment? From 59dfe793676268a1b74f6be314a535042a3eaabb Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 10 Sep 2025 10:53:58 -0700 Subject: [PATCH 08/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 341 +++++++++++++++++---------------- 1 file changed, 171 insertions(+), 170 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 945f9b7e..9e00b4d8 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -6,17 +6,17 @@ Recipes are external infrastructure-as-code (IaC) templates that operators register on a Radius Environment so developers can use them later for provisioning. They provide a mechanism for separation of concerns between developers and operators. -Today, Radius supports registering recipes individually, either via the `Applications.Core\environments` resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Some customers could have 1000s of environments and putting everything together manually for each environment is error prone. Recipes also do not have a lifecycle of their own and can be managed only by managing the environments pointing to them. +Today, Radius supports registering recipes individually, either via the `Applications.Core/environments` resource properties or the CLI (`rad recipe register`). For each Radius Environment, platform engineers have to piece together individual Recipes from scratch. Some customers could have 1000s of environments and putting everything together manually for each environment is error prone. Recipes also do not have a lifecycle of their own and can be managed only by managing the environments pointing to them. -This document proposes the design of a Recipe Pack as an first class resource type in Radius. The Recipe Pack enables bundling multiple recipe selections for different resource types into a reusable unit that can be referenced by environments. +This document proposes the design of a Recipe Pack as a first class resource type in Radius. The Recipe Pack enables bundling multiple recipe selections for different resource types into a reusable unit that can be referenced by environments. ## Terms and definitions -| Term | Definition | -| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Recipe | IaC templates that operators register on a Radius Environment | -| Recipe Pack| A collection of recipes that can be managed as an entity | -| RRT | [Radius Resource Type](https://docs.radapp.io/guides/author-apps/custom/overview/)| +| Term | Definition | +| ----------- | -------------------------------------------------------------------------------------------------- | +| Recipe | IaC templates that operators register on a Radius Environment | +| Recipe Pack | A collection of recipes that can be managed as an entity | +| RRT | [Radius Resource Type](https://docs.radapp.io/guides/author-apps/custom/overview/) | ## Objectives @@ -26,29 +26,27 @@ This document proposes the design of a Recipe Pack as an first class resource ty Provide Recipe Packs as a Radius feature to bundle multiple recipes as a single manageable entity into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). -- Radius should provide APIs to manage Radius.Core/recipePacks resource through CRUDL operations +- Radius should provide APIs to manage Radius.Core/recipePacks resource through CRUDL operations ### Non goals Recipe Packs would bundle together "recipes" as we understand them today. We do not cover recipe versioning / other recipe specific enhancements in this design. - ### User scenarios (optional) #### Registering several recipes to an environment -As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. This can be error prone when there are many recipes and environments. Radius should provide a way to bulk register( and manage) recipes. +As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. This can be error prone when there are many recipes and environments. Radius should provide a way to bulk register (and manage) recipes. -#### Registering recipes to multiple environment +#### Registering recipes to multiple environments -As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. I having 100s of environment which mostly use the same recipes. Piecing the same recipes together for each environment feels like rework. +As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. I have 100s of environments which mostly use the same recipes. Piecing the same recipes together for each environment feels like rework. ## Design ### Design Overview -We choose modeling recipe packs as a first class Radius resource of type -Radius.Core/recipePacks provisioned imperatively by Applications RP . [Alternatives considered](#alternatives-considered) section details some other options we considered. +We choose modeling recipe packs as a first class Radius resource of type Radius.Core/recipePacks provisioned imperatively by Applications RP. [Alternatives considered](#alternatives-considered) section details some other approaches we considered. Pros: @@ -58,26 +56,24 @@ Pros: - Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. - Imperative provisioning prevents users from accidentally experimenting with the resource schema - Cons: - This approach is a deviation from the current tooling approach for recipes. - Supporting recipe packs as a Applications RP type requires manual implementation of schema and API in contrast to modeling it as a dynamic resources. -At a very high level, this design approach needs the below steps +At a very high level, this design approach needs the below steps: * Add support for Radius.Core/recipePacks resource in Applications RP * Schema + API design and implementation * Support `rad cli` commands that enable CRUDL operations on resources of type Radius.Core/recipePacks * Design and support Radius.Core/environment schema in Applications RP * Support `rad cli` commands that enable managing Radius.Core/environment resources through CRUDL operations on this type of resource -* Support `rad cli` commands that enable registering recipe-packs to a `Radius.Core\environments` environment resource +* Support `rad cli` commands that enable registering recipe-packs to a `Radius.Core/environments` environment resource * Enhance Dynamic RP, Applications RP and UCP to support the feature. ### Schema and API design -As part of supporting Recipe Pack as a resource type, at a high-level, -We define a recipePacks.tsp (Note we currently do not have a Radius.Core namespace and we have to make code changes to set this namespace up with at-least environments and recipePacks) +As part of supporting Recipe Pack as a resource type, at a high-level, we define a recipePacks.tsp ```tsp namespace Radius.Core; @@ -126,7 +122,6 @@ enum RecipeKind { bicep: "bicep", } - @armResourceOperations interface RecipePacks { get is ArmResourceRead< @@ -159,12 +154,13 @@ interface RecipePacks { } ``` -* We choose map of resource types to their recipe configurations so that the relevant recipe can be easily accessed. -* We will not be supporting named recipes going forward as documented in [RRT feature spec](https://github.com/willtsai/design-notes-radius/blob/f9c98baf515263c27e7637131d7a48ae5a01b2c0/features/2025-02-user-defined-resource-type-feature-spec.md#user-story-7--registering-recipes). Therefore the `RecipeDefinition` model does not include a name. -* The operations are all Synchronous, since Recipe Pack a light weight configuration resource. - +* We choose a map of resource types to their recipe configurations so that the relevant recipe for a type can be easily accessed. + +* We will not be supporting named recipes going forward as documented in [RRT feature spec](https://github.com/willtsai/design-notes-radius/blob/f9c98baf515263c27e7637131d7a48ae5a01b2c0/features/2025-02-user-defined-resource-type-feature-spec.md#user-story-7--registering-recipes). Therefore the `RecipeDefinition` model does not include a name. + +* The operations are all Synchronous, since Recipe Pack is a lightweight configuration resource. -* createOrUpdate returns a `HTTP 201 Created` when recipe pack creation is successful and `HTTP 200 OK` for successful updates, with json payload representing the recipe pack resource created. +* createOrUpdate returns a `HTTP 201 Created` when recipe pack creation is successful and `HTTP 200 OK` for successful updates, with json payload representing the recipe pack resource created. [Sample to be added] @@ -172,7 +168,7 @@ interface RecipePacks { [Sample to be added] -* delete returns `HTTP 200 OK` upon successful deletion of recipe pack resource that corresponds to the resource ID. Other possible response is `HTTP 404 Not Found`. +* delete returns `HTTP 200 OK` upon successful deletion of recipe pack resource that corresponds to the resource ID. Other possible response is `HTTP 404 Not Found`. [Sample to be added] @@ -182,141 +178,136 @@ interface RecipePacks { #### Example -Below is a sample bicep definition of a recipe pack resource - +Below is a sample bicep definition of a recipe pack resource: -``` +```bicep resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { - name: 'computeRecipePack' - description: "Recipe Pack for deploying to Kubernetes." - properties: { - recipes: { - Radius.Compute/container: { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' - parameters: { - allowPlatformOptions: true - anIntegerParam : 1 - } - } - Radius.Security/secrets: { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' - } - Radius.Storage/volumes: { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' - } + name: 'computeRecipePack' + description: "Recipe Pack for deploying to Kubernetes." + properties: { + recipes: { + 'Radius.Compute/containers': { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' + parameters: { + allowPlatformOptions: true + anIntegerParam: 1 } + } + 'Radius.Security/secrets': { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' + } + 'Radius.Storage/volumes': { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' + } } + } } ``` ### Server Side changes -At a high level, below changes are necessary - +At a high level, below changes are necessary: #### UCP - Add support to UCP to route `Radius.Core\recipePacks` resource operations to Applications RP in below section. (might need more changes) +Add support to UCP to route `Radius.Core/recipePacks` resource operations to Applications RP in below section. (might need more changes) /radius/deploy/Chart/templates/ucp/configmaps.yaml ```yaml initialization: - planes: - - id: "/planes/radius/local" - properties: - resourceProviders: - Applications.Core: "http://applications-rp.radius-system:5443" - Applications.Dapr: "http://applications-rp.radius-system:5443" - Applications.Datastores: "http://applications-rp.radius-system:5443" - Applications.Messaging: "http://applications-rp.radius-system:5443" - Microsoft.Resources: "http://bicep-de.radius-system:6443" - kind: "UCPNative" + planes: + - id: "/planes/radius/local" + properties: + resourceProviders: + Applications.Core: "http://applications-rp.radius-system:5443" + Applications.Dapr: "http://applications-rp.radius-system:5443" + Applications.Datastores: "http://applications-rp.radius-system:5443" + Applications.Messaging: "http://applications-rp.radius-system:5443" + Microsoft.Resources: "http://bicep-de.radius-system:6443" + kind: "UCPNative" ``` #### Applications RP There are two prerequisites for implementing recipe packs: -1. Support new Radius.Core namespace. We would add Radius.Core namespace so that there is a transition time for users to move from Applications.Core/environments and recipes to Radius.Core/environment and Radius.Core/recipePacks. -Eventually Applications.Core will be deprecated and removed. +1. Support new Radius.Core namespace. We would add Radius.Core namespace so that there is a transition time for users to move from Applications.Core/environments and recipes to Radius.Core/environment and Radius.Core/recipePacks. Eventually Applications.Core will be deprecated and removed. 2. Radius.Core/environments design and implementation. -Below changes are needed for supporting recipe packs as new feature. +Below changes are needed for supporting recipe packs as new feature: + +1. Add schema /swagger changes to support the `Radius.Core/recipePacks` resource type ([typespec changes](#schema-and-api-design)) - 1. Add schema /swagger changes to support the `Radius.Core\recipePacks` resource type ([typepec changes](#schema-and-api-design)) +2. Create datamodel and convertors for handling recipe pack resource in /radius/`pkg/corerp/api/v20231001preview/ and /radius/pkg/corerp/datamodel/` + +3. Add controller support for creating/updating/listing/deleting the resource in `/radius/pkg/corerp/frontend/controller/`. Constraints for each operation are captured in [Recipe Pack Operations](#schema-and-api-design) - 2. Create datamodel and convertors for handling recipe pack resource in /radius/pkg/corerp/api/v20231001preview/ and /radius/pkg/corerp/datamodel/ - - 3. Add controller support for creating/updating/listing/deleting the resource in `/radius/pkg/corerp/frontend/controller/`. Constraints for each operation are captured in [Recipe Pack Operations](#schema-and-api-design) +4. When an Applications RP supported resource is being deployed, the resource could be recipe based (portable) or non recipe based today (applications and environment). For recipe based resources, `/radius/pkg/portableresources/backend/controller/createorupdateresource.go` should be updated to: + 1. fetch environment's recipe-pack ids + 2. get recipe-pack resource one at a time, stopping as soon as a match for resource-type is found. + 3. Then it should populate RecipeMetaData appropriately before calling the engine. - 4. When an Applications RP supported resource is being deployed, the resource could be recipe based (portable) or non recipe based today (applications and environment). For recipe based resources, `/radius/pkg/portableresources/backend/controller/createorupdateresource.go` should be updated to - 1. fetch environment's recipe-pack ids - 2. get recipe-pack resource one at a time, stopping as soon as a match for resource-type is found. - 3. Then it should populate RecipeMetaData appropriately before calling the engine. This flow should come in place if the environment used for deploying is of type Radius.Core/environments only. - - -As part of Radius.Core/environments design/ implementation below points should be considered: - - 1. Finalize the `Radius.Core\environments` details and then - 2. Add schema / swagger changes to support the `Radius.Core\environments` resource type +As part of Radius.Core/environments design/implementation below points should be considered: - 3. Add convertors for handling conversions from and to version agnostic data model. +1. Finalize the `Radius.Core/environments` details and then - 4. Add backend/controller support for creating/updating/deleting the resource. +2. Add schema / swagger changes to support the `Radius.Core/environments` resource type - 5. rad env register should support registering a recipe pack to Radius.Core/environments resource, and disallow recipes. +3. Add convertors for handling conversions from and to version agnostic data model. +4. Add backend/controller support for creating/updating/deleting the resource. +5. rad env register should support registering a recipe pack to Radius.Core/environments resource, and disallow recipes. #### Dynamic RP changes -1. In Dynamic RP, while deploying a dynamic resource - 1. Add support to look up the `Radius.Core\environments` that is in use, fetch environment's recipe-pack ids +1. In Dynamic RP, while deploying a dynamic resource: + 1. Add support to look up the `Radius.Core/environments` that is in use, fetch environment's recipe-pack ids 2. Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. 3. Use the recipe information just fetched and construct recipe details that can be passed to the existing recipe engine mechanism. #### Other components -2. No changes to controller or DE. - +No changes to controller or DE. ### CLI design -We should introduce rad cli commands to help manage recipe-packs. -We should add documentation to rad recipe commands indicating their future deprecation plan. +We should introduce rad cli commands to help manage recipe-packs. We should add documentation to rad recipe commands indicating their future deprecation plan. -1. Creating a recipe-pack should work once we create and register the recipe pack schema. +1. Creating a recipe-pack should work once we create and register the recipe pack schema: -``` +```bicep computeRecipePack.bicep: resource computeRecipePack 'Radius.Core/recipePacks@2025-05-01-preview' = { - name: 'computeRecipePack' - description: "Recipe Pack for deploying to Kubernetes." - properties: { - recipes: [ - Radius.Compute/container: { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' - parameters: { - allowPlatformOptions: true - } - } - Radius.Security/secrets: { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' - } - Radius.Storage/volumes: { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' - } - ] + name: 'computeRecipePack' + description: "Recipe Pack for deploying to Kubernetes." + properties: { + recipes: { + 'Radius.Compute/containers': { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' + parameters: { + allowPlatformOptions: true + } + } + 'Radius.Security/secrets': { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' + } + 'Radius.Storage/volumes': { + recipeKind: 'terraform' + recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' + } } + } } rad deploy computeRecipePack.bicep @@ -324,47 +315,57 @@ rad deploy computeRecipePack.bicep Note: rad recipe-pack create command could be added in future. For now, we are using rad deploy to create recipe packs. -1. +2. Show recipe pack details: + ``` $ rad recipe-pack show computeRecipePack -RESOURCE TYPE GROUP STATE -computeRecipePack Radius.Core/recipePacks default Succeeded +RESOURCE TYPE GROUP STATE +computeRecipePack Radius.Core/recipePacks default Succeeded RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 - ``` -3. +3. List recipe packs: + ``` $ rad recipe-pack list [optionally -e myenv] -RESOURCE TYPE GROUP STATE -computeRecipePack Radius.Core/recipePacks default Succeeded -dataRecipePack. Radius.Core/recipePacks default Succeeded - +RESOURCE TYPE GROUP STATE +computeRecipePack Radius.Core/recipePacks default Succeeded +dataRecipePack Radius.Core/recipePacks default Succeeded ``` If no -e is specified, this command should list all recipe packs in current scope. -4. rad recipe-pack delete +4. Delete recipe pack: + +``` +$ rad recipe-pack delete +``` + +We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. -We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. +5. Register recipe pack to environment: + +``` +$ rad env register recipe-pack recipe-pack-name [-g group-id] +``` +The command should use the resource ID to identify the environment is `Radius.Core\environment` resource and only then allow recipe pack registration. If the namespace is `Applications.Core`, it should work as it does today. -5. rad env register recipe-pack recipe-pack-name [-g group id] We specify group resource id if the recipe-pack is in a different scope from the environment. -6. rad env show should be updated +6. Show environment details: Based on whether the environment namespace is Applications.Core or Radius.Core, the outputs differ. Eventually Applications.Core support will be removed. ``` $ rad environment show my-env -RESOURCE TYPE GROUP STATE -my-env Radius.Core/environments default Succeeded +RESOURCE TYPE GROUP STATE +my-env Radius.Core/environments default Succeeded RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION computeRecipePack Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 @@ -373,7 +374,8 @@ computeRecipePack Radius.Storage/volumes terraform dataRecipePack Radius.Data/redisCaches terraform https://github.com/project-radius/resource-types-contrib.git//recipes/data/redisCaches?ref=v0.48 ``` -7. rad recipe list +7. List recipes in environment: + ``` $ rad recipe list -environment my-env RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION @@ -384,9 +386,9 @@ dataRecipePack Radius.Data/redisCaches terraform networkingRecipePack Radius.Compute/gateways terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/gateways?ref=v0.48 ``` -8. rad init +8. Initialize Radius: -Today, rad init works as show below: +Today, rad init works as shown below: ``` Initializing Radius. This may take a minute or two... @@ -400,28 +402,32 @@ Initializing Radius. This may take a minute or two... ⏳ Scaffold application resource-types-contrib ⏳ Update local configuration ``` + The default environment created is initialized with a "recipe pack" which is a bunch of kubernetes recipes. -We are choosing to keep the same behavior. But behind the scenes rad init would create. recipe pack resource, with recipe links we use today to construct recipe properties and add this recipe pack's resource id to the environment. +We are choosing to keep the same behavior. But behind the scenes rad init would create a recipe pack resource, with recipe links we use today to construct recipe properties and add this recipe pack's resource id to the environment. -Providing an option for az/ aws based recipe packs requires considerable work and would be a future follow up to the feature. +Providing an option for az/aws based recipe packs requires considerable work and would be a future follow up to the feature. ### Graph support -### Logging/ Tracing support +Recipe packs will be displayed in application graphs as first-class resources with their own lifecycle and relationships to environments. + +### Logging/Tracing support + +Standard logging and tracing will be implemented for all recipe pack operations through the existing Applications RP infrastructure. ### Breaking changes -* Once we support recipe packs, the Radius.Core environments will allow only registration of recipe-packs and not a single recipe. Applications.Core environments will continue to work as it does today and support recipe registration but will be deprecated over time allowing transition time for customers move from recipes to recipe packs. +* Once we support recipe packs, the Radius.Core environments will allow only registration of recipe-packs and not a single recipe. Applications.Core environments will continue to work as it does today and support recipe registration but will be deprecated over time allowing transition time for customers to move from recipes to recipe packs. * We will drop the support for named recipe - a way to register multiple recipes for the same resource-type in a single environment. - ## Alternatives considered -Below options were considered as alternatives to modeling recipe pack as a first class RRT - +Below options were considered as alternatives to modeling recipe pack as a first class RRT: -1. embed all recipe mappings inline in the Environment +### 1. Embed all recipe mappings inline in the Environment This is similar to what we have today. We could introduce a yaml spec similar to below, and when user executes a `rad recipe-pack register` this spec could be parsed and all recipes added to environment. @@ -430,26 +436,26 @@ name: aci-production-pack version: 1.0.0 description: "Recipe Pack for deploying to ACI in production." recipes: - - resourceType: "Radius.Compute/containers@2025-05-01-preview" + - resourceType: "Radius.Compute/containers@2025-05-01-preview" recipeKind: "bicep" recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-container:1.2.0" parameters: - cpu: "1.0" - memoryInGB: "2.0" - environmentVariables: + cpu: "1.0" + memoryInGB: "2.0" + environmentVariables: LOG_LEVEL: "Information" - # Optional: allow platform-specific options like containerGroupProfile for ACI - allowPlatformOptions: true - - resourceType: "Radius.Compute/gateways@2025-05-01-preview" + # Optional: allow platform-specific options like containerGroupProfile for ACI + allowPlatformOptions: true + - resourceType: "Radius.Compute/gateways@2025-05-01-preview" recipeKind: "bicep" recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-gateway:1.1.0" parameters: - sku: "Standard_v2" - - resourceType: "Radius.Security/secrets@2025-05-01-preview" + sku: "Standard_v2" + - resourceType: "Radius.Security/secrets@2025-05-01-preview" recipeKind: "bicep" recipeLocation: "oci://ghcr.io/my-org/recipes/azure/keyvault-secretstore:1.0.0" parameters: - skuName: "premium" + skuName: "premium" ``` Pros: @@ -457,17 +463,13 @@ Pros: - Most compatible to what we have in Radius today and hence the fastest approach. - Solves the requirement for bulk registering recipes using single command with a one time effort of creating the yaml manifest - Cons: -- Environment still stays a bloated object. Environment resource houses a lot of other properties and we could potentially risk hiting the mechanical limits that apply to serializing objects. - +- Environment still stays a bloated object. Environment resource houses a lot of other properties and we could potentially risk hitting the mechanical limits that apply to serializing objects. - Add Radius commands to publish recipe-packs, similar to what we have for recipes today. +- A list of recipes could potentially be managed as a collection, including having its own rbac and appearance in app graph. The above approach does not allow for that possibility. -- a list of recipes could potentially be managed as a collection, including having its own rbac and appearance in app graph. The above approach does not allow for that possibility. - - -1. store a URL to a YAML manifest in the Environment +### 2. Store a URL to a YAML manifest in the Environment We could fetch the yaml when needed, and use the available recipe. @@ -480,9 +482,9 @@ Pros: Cons: -- For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could cache the list and construct an im-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. +- For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could cache the list and construct an in-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. -1. model recipe packs as Radius Resource type provided by Dynamic RP. +### 3. Model recipe packs as Radius Resource type provided by Dynamic RP Pros: @@ -499,41 +501,40 @@ In general, Radius.Core namespace has resources whose schema should be non-edita ## Test plan - +[To be completed] ## Security - +[To be completed] ## Compatibility (optional) +[To be completed] ## Monitoring +[To be completed] ## Development plan - - +[To be completed] ## Open issues +[To be completed] -## notes/questions for myself (to be deleted) -- recipe-pack : RRT or NOT? same question as RRT in the Radius.Config namespace (app, env). These types are not meant to be edited by users, and should be as defined by Radius so that Radius can work. -- rad init today says installing a "recipe-pack" - might need changes here to enable choosing a pack. +## notes/questions for myself (to be deleted before merging) + +- recipe-pack : RRT or NOT? same question as RRT in the Radius.Config namespace (app, env). These types are not meant to be edited by users, and should be as defined by Radius so that Radius can work. (imperatative) +- rad init today says installing a "recipe-pack" - might need changes here to enable choosing a pack. (retain behavior) - rad init / install must be updated to create the recipe pack resource type ( as part of registering manifests logic we have today) -- if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. -- would environment and recipe pack ever have different rbac? should we "allow" recipepack is in different radius resource grpup from that of environment? +- if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. (in future) +- would environment and recipe pack ever have different rbac? should we "allow" recipepack is in different radius resource grpup from that of environment? (yes , with -g) - - prereq: finalize new environment design - handling recipe-packs with dup recipes. at the time of creation, of recipe pack, it could have dups with another recipe-pack. But we have to dtect dups at the time of registering to env. -- we are moving away from named recipes. If a customer wishes to use same env for two applications, these application teams have their own recipes, then would we advice them to create 2 enviroments ? We could also guide them to a naming like contoso-recipe-pack and cool-prod-recipe-pack. But this would either require us to allow for duplicate recipes between packs, or require multiple teams to coordinate and ensure their types are different? -- now that the "unit" of importing recipes is recipe pack, would we "contrib" recipe pack manifests? -- would we think about enforcing a size limit on recipe pack? how many recipes it can have ? -- - should recipe-pack resource have a list of env ids to which it belongs? typically, RRTs have an app id or env id. -- - cli -support versus deploying through bicep - - - - +- we are moving away from named recipes. If a customer wishes to use same env for two applications, these application teams have their own recipes, then would we advice them to create 2 enviroments ? We could also guide them to a naming like contoso-recipe-pack and cool-prod-recipe-pack. But this would either require us to allow for duplicate recipes between packs, or require multiple teams to coordinate and ensure their types are different? (its is upto the teams to decide how they want to organize) +- now that the "unit" of importing recipes is recipe pack, would we "contrib" recipe pack manifests? (yes) +- would we think about enforcing a size limit on recipe pack? how many recipes it can have ? (not now) +- - should recipe-pack resource have a list of env ids to which it belongs? typically, RRTs have an app id or env id. (no, causes a cycle) +- - cli -support versus deploying through bicep (create cmd can come later for recipe pack) \ No newline at end of file From 9f5c4a9160d458d8f8b9cfa7403e2209d926152a Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Fri, 12 Sep 2025 15:25:56 -0700 Subject: [PATCH 09/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 349 +++++++++++++++++++++++---------- 1 file changed, 244 insertions(+), 105 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 9e00b4d8..b1c192dc 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -42,24 +42,110 @@ As an operator I am responsible for creating Radius Environments using which dev As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. I have 100s of environments which mostly use the same recipes. Piecing the same recipes together for each environment feels like rework. +#### Sharing Recipe Packs Across Environments and Organizations + +As an operator, I want to share and reuse Recipe Packs across different environments or organizations. Instead of manually registering individual recipes, I can import a pre-bundled Recipe Pack (e.g., for Kubernetes or ACI) published by a provider or another team. This streamlines environment setup, reduces errors, and ensures + ## Design ### Design Overview -We choose modeling recipe packs as a first class Radius resource of type Radius.Core/recipePacks provisioned imperatively by Applications RP. [Alternatives considered](#alternatives-considered) section details some other approaches we considered. +**Prefered Approach:** -Pros: +We choose modeling recipe packs as a first class Radius resource of type Radius.Core/recipePacks provisioned imperatively by Applications RP. Consequentilly their schema and operations are fixed and not editable. +Pros: - Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource - As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and RBAC independent of environments. - Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. - Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. -- Imperative provisioning prevents users from accidentally experimenting with the resource schema +- Imperative provisioning ensures strict control over schema and behavior, preventing users from breaking core Radius constructs. +- Clear separation between user-extensible and core system resources, improving maintainability. Cons: - This approach is a deviation from the current tooling approach for recipes. -- Supporting recipe packs as a Applications RP type requires manual implementation of schema and API in contrast to modeling it as a dynamic resources. +- Supporting recipe packs as a Applications RP type requires manual implementation of schema and API in contrast to modeling it as a dynamic resources. Versioning support is not automatic as in case of dynamic resources. + +In general, Radius.Core namespace has resources whose schema should be non-editable so that Radius can work as expected, for example Applications, Environments and recipePacks. These resources must be provisioned imperatively by Applications RP and their schema must be protected. + +**Alternatives considered** + +Below options were considered as alternatives to modeling recipe pack as a first class Applications RP resource. + +***Model recipe packs as first class Radius Resource type provided by Dynamic RP*** + +Pros: + +- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource +- As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independent of environments. +- Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. +- Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. +- API versioning is automatically supported + +Cons: + +- While this brings in just as many advantages as the chosen design approach plus automatic API versioning, RRTs can have their schema modified using rad resource-type commands. We would have to find ways to prevent this from happening. + +***Embed all recipe mappings inline in the Environment*** + +This is similar to what we have today. We could introduce a yaml spec similar to below, and when user executes a `rad recipe-pack register` this spec could be parsed and all recipes added to environment. + +```yaml +name: aci-production-pack +version: 1.0.0 +description: "Recipe Pack for deploying to ACI in production." +recipes: + - resourceType: "Radius.Compute/containers@2025-05-01-preview" + recipeKind: "bicep" + recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-container:1.2.0" + parameters: + cpu: "1.0" + memoryInGB: "2.0" + environmentVariables: + LOG_LEVEL: "Information" + # Optional: allow platform-specific options like containerGroupProfile for ACI + allowPlatformOptions: true + - resourceType: "Radius.Compute/gateways@2025-05-01-preview" + recipeKind: "bicep" + recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-gateway:1.1.0" + parameters: + sku: "Standard_v2" + - resourceType: "Radius.Security/secrets@2025-05-01-preview" + recipeKind: "bicep" + recipeLocation: "oci://ghcr.io/my-org/recipes/azure/keyvault-secretstore:1.0.0" + parameters: + skuName: "premium" +``` + +Pros: + +- Most compatible to what we have in Radius today and hence the fastest approach. +- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the yaml manifest + +Cons: + +- Environment still stays a bloated object. Environment resource houses a lot of other properties and we could potentially risk hitting the mechanical limits that apply to serializing objects. +- Add Radius commands to publish recipe-packs, similar to what we have for recipes today. +- A list of recipes could potentially be managed as a collection, including having its own rbac and appearance in app graph. The above approach does not allow for that possibility. + +***Store a URL to a YAML manifest in the Environment*** + +We could fetch the yaml when needed, and use the available recipe. + +`rad environment update my-env --recipe-packs aci-production-pack='git::https://github.com/my-org/recipe-packs.git//aci-production-pack.yaml?ref=1.0.0'` + +Pros: + +- Helps manage the size of environment resource +- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the yaml manifest + +Cons: + +- For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could cache the list and construct an in-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. + +### High level flow + At a very high level, this design approach needs the below steps: @@ -160,23 +246,9 @@ interface RecipePacks { * The operations are all Synchronous, since Recipe Pack is a lightweight configuration resource. -* createOrUpdate returns a `HTTP 201 Created` when recipe pack creation is successful and `HTTP 200 OK` for successful updates, with json payload representing the recipe pack resource created. - -[Sample to be added] - -* get returns `HTTP 200 OK` + payload of the serialized recipe pack resource that corresponds to the resource ID. - -[Sample to be added] - -* delete returns `HTTP 200 OK` upon successful deletion of recipe pack resource that corresponds to the resource ID. Other possible response is `HTTP 404 Not Found`. - -[Sample to be added] - -* listByScope returns `HTTP 200 OK` with payload containing a list of recipe packs in the given scope. -[Sample to be added] -#### Example +#### Examples Below is a sample bicep definition of a recipe pack resource: @@ -207,6 +279,142 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { } ``` +``` +resource env 'Radius.Core/environments@2025-05-01-preview' = { + name: 'my-env' + properties: { ++ // The recipePacks property is an array of Recipe Pack IDs ++ recipePacks: [computeRecipePack.id, dataRecipePack.id] + // Other properties + } +} +``` + + +Below are sample HTTP requests for managing a recipe pack resource + +CREATE request: + +``` +curl -X PUT \ + "http://localhost:9000/apis/api.ucp.dev/v1alpha3/planes/radius/local/resourceGroups/default/providers/Radius.Core/recipePacks/testrecipepack?api-version=2023-10-01-preview" \ + -H "Content-Type: application/json" \ + -d '{ + "location": "global", + "properties": { + "description": "Test recipe pack with sample recipes", + "recipes": { + "Applications.Datastores/sqlDatabases": { + "recipeKind": "terraform", + "recipeLocation": "https://github.com/example/recipes/sql-database", + "parameters": { + "size": "small", + "backup": false + } + }, + "Applications.Datastores/redisCaches": { + "recipeKind": "bicep", + "recipeLocation": "https://github.com/example/recipes/redis-cache.bicep", + "parameters": { + "tier": "basic" + } + } + } + } + }' + ``` + +CREATE response: + +```json +{ + "id": "/planes/radius/local/resourcegroups/default/providers/Radius.Core/recipePacks/testrecipepack", + "location": "global", + "name": "testrecipepack", + "properties": { + "description": "Test recipe pack with sample recipes", + "provisioningState": "Succeeded", + "recipes": { + "Applications.Datastores/redisCaches": { + "parameters": { + "tier": "basic" + }, + "recipeKind": "bicep", + "recipeLocation": "https://github.com/example/recipes/redis-cache.bicep" + }, + "Applications.Datastores/sqlDatabases": { + "parameters": { + "backup": false, + "size": "small" + }, + "recipeKind": "terraform", + "recipeLocation": "https://github.com/example/recipes/sql-database" + } + } + }, + "systemData": { + "createdAt": "0001-01-01T00:00:00Z", + "createdBy": "", + "createdByType": "", + "lastModifiedAt": "0001-01-01T00:00:00Z", + "lastModifiedBy": "", + "lastModifiedByType": "" + }, + "tags": {}, + "type": "Applications.Core/recipePacks" +} + +``` + +READ request: + +``` +nithya@MacBook-Pro ~ % curl -X GET\ + "http://localhost:9000/apis/api.ucp.dev/v1alpha3/planes/radius/local/resourceGroups/default/providers/Radius.Core/recipePacks/testrecipepack?api-version=2023-10-01-preview" +``` + +READ response: + +```json +{ + "id": "/planes/radius/local/resourcegroups/default/providers/Radius.Core/recipePacks/testrecipepack", + "location": "global", + "name": "testrecipepack", + "properties": { + "description": "Test recipe pack with sample recipes", + "provisioningState": "Succeeded", + "recipes": { + "Applications.Datastores/redisCaches": { + "parameters": { + "tier": "basic" + }, + "recipeKind": "bicep", + "recipeLocation": "https://github.com/example/recipes/redis-cache.bicep" + }, + "Applications.Datastores/sqlDatabases": { + "parameters": { + "backup": false, + "size": "small" + }, + "recipeKind": "terraform", + "recipeLocation": "https://github.com/example/recipes/sql-database" + } + } + }, + "systemData": { + "createdAt": "0001-01-01T00:00:00Z", + "createdBy": "", + "createdByType": "", + "lastModifiedAt": "0001-01-01T00:00:00Z", + "lastModifiedBy": "", + "lastModifiedByType": "" + }, + "tags": {}, + "type": "Applications.Core/recipePacks" +} +``` + + ### Server Side changes At a high level, below changes are necessary: @@ -246,13 +454,12 @@ Below changes are needed for supporting recipe packs as new feature: 2. Create datamodel and convertors for handling recipe pack resource in /radius/`pkg/corerp/api/v20231001preview/ and /radius/pkg/corerp/datamodel/` 3. Add controller support for creating/updating/listing/deleting the resource in `/radius/pkg/corerp/frontend/controller/`. Constraints for each operation are captured in [Recipe Pack Operations](#schema-and-api-design) + +4. Update applications_core.yaml manifest to include the new type. -4. When an Applications RP supported resource is being deployed, the resource could be recipe based (portable) or non recipe based today (applications and environment). For recipe based resources, `/radius/pkg/portableresources/backend/controller/createorupdateresource.go` should be updated to: - 1. fetch environment's recipe-pack ids - 2. get recipe-pack resource one at a time, stopping as soon as a match for resource-type is found. - 3. Then it should populate RecipeMetaData appropriately before calling the engine. +5. When an Applications RP supported resource is being deployed, the resource could be recipe based (portable) or non recipe based today (applications and environment). For recipe based resources, `radius/pkg/rp/util/recipepacks.go` should be created, and have ability to fetch recipepacks, similar to `/radius/pkg/rp/util/environment.go`. Then `/radius/env-sup-rp/pkg/recipes/configloader/environment.go#L72` `getConfiguration` function must be updated to fetch the recipe pack resource one by one, and iterate until a recipe pack containing recipe for resource type of interest is found. - This flow should come in place if the environment used for deploying is of type Radius.Core/environments only. +This flow should come in place if the environment used for deploying is of type Radius.Core/environments only. We retain current behavior for Applications.Core/environments. As part of Radius.Core/environments design/implementation below points should be considered: @@ -268,11 +475,15 @@ As part of Radius.Core/environments design/implementation below points should be #### Dynamic RP changes -1. In Dynamic RP, while deploying a dynamic resource: - 1. Add support to look up the `Radius.Core/environments` that is in use, fetch environment's recipe-pack ids - 2. Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. - 3. Use the recipe information just fetched and construct recipe details that can be passed to the existing recipe engine mechanism. - +In Dynamic RP, while deploying a dynamic resource: + +1. Add support to look up the `Radius.Core/environments` that is in use, fetch environment's recipe-pack ids +2. Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. +3. Use the recipe information just fetched and construct recipe details that can be passed to the existing recipe engine mechanism. + +Since Dynamic RP shares the recipe engine code with Applications RP, Dynamic Resources should be able to avail recipe packs once Applications RP code changes are complete. + + #### Other components No changes to controller or DE. @@ -415,89 +626,17 @@ Recipe packs will be displayed in application graphs as first-class resources wi ### Logging/Tracing support -Standard logging and tracing will be implemented for all recipe pack operations through the existing Applications RP infrastructure. +Standard logging and tracing will be implemented for all recipe pack operations through the existing Applications RP logging/tracing infrastructure. ### Breaking changes * Once we support recipe packs, the Radius.Core environments will allow only registration of recipe-packs and not a single recipe. Applications.Core environments will continue to work as it does today and support recipe registration but will be deprecated over time allowing transition time for customers to move from recipes to recipe packs. -* We will drop the support for named recipe - a way to register multiple recipes for the same resource-type in a single environment. - -## Alternatives considered - -Below options were considered as alternatives to modeling recipe pack as a first class RRT: - -### 1. Embed all recipe mappings inline in the Environment - -This is similar to what we have today. We could introduce a yaml spec similar to below, and when user executes a `rad recipe-pack register` this spec could be parsed and all recipes added to environment. - -```yaml -name: aci-production-pack -version: 1.0.0 -description: "Recipe Pack for deploying to ACI in production." -recipes: - - resourceType: "Radius.Compute/containers@2025-05-01-preview" - recipeKind: "bicep" - recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-container:1.2.0" - parameters: - cpu: "1.0" - memoryInGB: "2.0" - environmentVariables: - LOG_LEVEL: "Information" - # Optional: allow platform-specific options like containerGroupProfile for ACI - allowPlatformOptions: true - - resourceType: "Radius.Compute/gateways@2025-05-01-preview" - recipeKind: "bicep" - recipeLocation: "oci://ghcr.io/my-org/recipes/core/aci-gateway:1.1.0" - parameters: - sku: "Standard_v2" - - resourceType: "Radius.Security/secrets@2025-05-01-preview" - recipeKind: "bicep" - recipeLocation: "oci://ghcr.io/my-org/recipes/azure/keyvault-secretstore:1.0.0" - parameters: - skuName: "premium" -``` - -Pros: - -- Most compatible to what we have in Radius today and hence the fastest approach. -- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the yaml manifest - -Cons: - -- Environment still stays a bloated object. Environment resource houses a lot of other properties and we could potentially risk hitting the mechanical limits that apply to serializing objects. -- Add Radius commands to publish recipe-packs, similar to what we have for recipes today. -- A list of recipes could potentially be managed as a collection, including having its own rbac and appearance in app graph. The above approach does not allow for that possibility. - -### 2. Store a URL to a YAML manifest in the Environment - -We could fetch the yaml when needed, and use the available recipe. +We could also explore providing some tools to create the new environment resource and recipe packs based on existing environment and recipe information to ease transition. -`rad environment update my-env --recipe-packs aci-production-pack='git::https://github.com/my-org/recipe-packs.git//aci-production-pack.yaml?ref=1.0.0'` - -Pros: - -- Helps manage the size of environment resource -- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the yaml manifest - -Cons: - -- For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could cache the list and construct an in-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. - -### 3. Model recipe packs as Radius Resource type provided by Dynamic RP - -Pros: - -- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource -- As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independent of environments. -- Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. -- Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. - -Cons: +* We will drop the support for named recipe - a way to register multiple recipes for the same resource-type in a single environment. -- While this brings in just as many advantages as the chosen design approach, RRTs can have their schema modified using rad resource-type commands. We would have to find ways to prevent this from happening. -In general, Radius.Core namespace has resources whose schema should be non-editable so that Radius can work as expected, for example Applications, Environments and recipePacks. These resources must be provisioned imperatively by Applications RP. ## Test plan @@ -517,7 +656,7 @@ In general, Radius.Core namespace has resources whose schema should be non-edita ## Development plan -[To be completed] +1. ## Open issues From 830639105bb3c18fa79aa9e671ba6b39646e0e09 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Fri, 12 Sep 2025 19:01:45 -0700 Subject: [PATCH 10/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index b1c192dc..da7c3464 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -50,7 +50,10 @@ As an operator, I want to share and reuse Recipe Packs across different environm ### Design Overview -**Prefered Approach:** +In general, Radius.Core namespace has resources whose schema should be non-editable so that Radius can work as expected, for example Applications, Environments and recipePacks. These resources must be provisioned imperatively and their schema must be protected. With this constraint in mind, 2 approaches are possible: + + +***Preferred Approach 1*** We choose modeling recipe packs as a first class Radius resource of type Radius.Core/recipePacks provisioned imperatively by Applications RP. Consequentilly their schema and operations are fixed and not editable. @@ -67,13 +70,9 @@ Cons: - This approach is a deviation from the current tooling approach for recipes. - Supporting recipe packs as a Applications RP type requires manual implementation of schema and API in contrast to modeling it as a dynamic resources. Versioning support is not automatic as in case of dynamic resources. -In general, Radius.Core namespace has resources whose schema should be non-editable so that Radius can work as expected, for example Applications, Environments and recipePacks. These resources must be provisioned imperatively by Applications RP and their schema must be protected. - -**Alternatives considered** +***Preferred Approach 2*** -Below options were considered as alternatives to modeling recipe pack as a first class Applications RP resource. - -***Model recipe packs as first class Radius Resource type provided by Dynamic RP*** +We choose modeling recipe packs as a first class Radius resource of type Radius.Core/recipePacks provisioned by Dynamic RP. Pros: @@ -82,10 +81,14 @@ Pros: - Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. - Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. - API versioning is automatically supported +- DynamicRP already supports "ManualProvsiioning" as a capability for resource that do not need recipe provisioning. Cons: -- While this brings in just as many advantages as the chosen design approach plus automatic API versioning, RRTs can have their schema modified using rad resource-type commands. We would have to find ways to prevent this from happening. +- While this brings in just as many advantages as the chosen design approach plus automatic API versioning, +- RRTs can have their schema modified using rad resource-type commands. We could choose to implement schema validation to make sure users do not run rad resource-type CRUD operations on Radius.Core namespace. + +### Other alternatives considered ***Embed all recipe mappings inline in the Environment*** From 07ee472edbf1ae4f2a807a14e3349c3aba9faae0 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Fri, 12 Sep 2025 19:03:16 -0700 Subject: [PATCH 11/24] WIP Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index da7c3464..284678b8 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -86,7 +86,7 @@ Pros: Cons: - While this brings in just as many advantages as the chosen design approach plus automatic API versioning, -- RRTs can have their schema modified using rad resource-type commands. We could choose to implement schema validation to make sure users do not run rad resource-type CRUD operations on Radius.Core namespace. +- RRTs can have their schema modified using rad resource-type commands. We could choose to implement schema validation to make sure users cannot not use rad resource-type CRUD operations on Radius.Core namespace. ### Other alternatives considered From df0665c4897634215a0c8ff50d23ba2fb4402390 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Mon, 15 Sep 2025 10:03:57 -0700 Subject: [PATCH 12/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 37 ++++++++++++---------------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 284678b8..f0122adf 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -51,42 +51,31 @@ As an operator, I want to share and reuse Recipe Packs across different environm ### Design Overview In general, Radius.Core namespace has resources whose schema should be non-editable so that Radius can work as expected, for example Applications, Environments and recipePacks. These resources must be provisioned imperatively and their schema must be protected. With this constraint in mind, 2 approaches are possible: +1. Radius.Core/recipePacks provisioned imperatively by Applications RP +2. Radius.Core/recipePacks provisioned Manually by Dynamic RP +Both approaches have the below benefits: -***Preferred Approach 1*** - -We choose modeling recipe packs as a first class Radius resource of type Radius.Core/recipePacks provisioned imperatively by Applications RP. Consequentilly their schema and operations are fixed and not editable. - -Pros: - Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource - As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and RBAC independent of environments. - Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. - Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. -- Imperative provisioning ensures strict control over schema and behavior, preventing users from breaking core Radius constructs. -- Clear separation between user-extensible and core system resources, improving maintainability. +- Helps with change isolation, since recipe pack updates are isolated from env updates. +- Promotes reusablity since multiple environments can point to a recipe pack using the recipe pack ID. -Cons: - -- This approach is a deviation from the current tooling approach for recipes. -- Supporting recipe packs as a Applications RP type requires manual implementation of schema and API in contrast to modeling it as a dynamic resources. Versioning support is not automatic as in case of dynamic resources. +Below table highlights the trade offs: -***Preferred Approach 2*** +| Aspect | Applications RP provisioning| Dynamic RP provisioning | +|---------|-----------| ------------------------------------------| +| **Tooling complexity** | ❌ Higher (TSP, converter, schema, API implemenetations needed) | ✅ Lower (YAML only, dynamic resource controllers reused)| +| **Versioning** | ❌ requires versioning support in Radius |✅ Supports schema versioning| +| **Custom implementation for operations** | ✅ can customize details of CRUDL| ❌ falls back on dynamic resource controllers | -We choose modeling recipe packs as a first class Radius resource of type Radius.Core/recipePacks provisioned by Dynamic RP. +Based on the above differences, *we choose Radius.Core/recipePacks to be provisioned imperatively by Applications RP as a first class Radius resource*. The main reason for this decision is that Radius Core resources such as enviroments and recipe-packs could have complex and custom deletion logic compared to what a dynamic resource deletion does. For instance, we need a cascase of deletion when an environment is deleted, or we might want to restrict deleting a recipe pack that is referenced in one or more environment. It is important to support robust core management operations of these resources where as the versioning can follow once Radius versioning support is available. -Pros: +We should make sure the rad resource-type commands cannot alter the schema of these types as part of schema validation (this namespace is reserved for Radius's use). -- Solves the requirement for bulk registering recipes using single command with a one time effort of creating the recipe pack resource -- As first class resource, recipe packs would be displayed in app graphs. They can also have their own lifecycle and rbac independent of environments. -- Helps reduce the size of environment resource, which could reach serialization limits with tons of recipes. -- Helps reduce overall size of Radius datastore, since common recipe information could now be stored as a single resource instead of being duplicated across several environments. -- API versioning is automatically supported -- DynamicRP already supports "ManualProvsiioning" as a capability for resource that do not need recipe provisioning. - -Cons: -- While this brings in just as many advantages as the chosen design approach plus automatic API versioning, -- RRTs can have their schema modified using rad resource-type commands. We could choose to implement schema validation to make sure users cannot not use rad resource-type CRUD operations on Radius.Core namespace. ### Other alternatives considered From de0f49e2c3ef53ae47769f5062dc704358e6ea9c Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 17 Sep 2025 10:06:27 -0700 Subject: [PATCH 13/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 82 +++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index f0122adf..bb65dda1 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -26,7 +26,8 @@ This document proposes the design of a Recipe Pack as a first class resource typ Provide Recipe Packs as a Radius feature to bundle multiple recipes as a single manageable entity into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). -- Radius should provide APIs to manage Radius.Core/recipePacks resource through CRUDL operations + - Radius should provide APIs to manage Radius.Core/recipePacks resource through CRUDL operations + ### Non goals @@ -44,7 +45,7 @@ As an operator I am responsible for creating Radius Environments using which dev #### Sharing Recipe Packs Across Environments and Organizations -As an operator, I want to share and reuse Recipe Packs across different environments or organizations. Instead of manually registering individual recipes, I can import a pre-bundled Recipe Pack (e.g., for Kubernetes or ACI) published by a provider or another team. This streamlines environment setup, reduces errors, and ensures +As an operator, I want to share and reuse Recipe Packs across different environments or organizations. Instead of manually registering individual recipes, I can import a pre-bundled Recipe Pack (e.g., for Kubernetes or ACI) published by a provider or another team. This streamlines environment setup and reduces errors. ## Design @@ -71,9 +72,9 @@ Below table highlights the trade offs: | **Versioning** | ❌ requires versioning support in Radius |✅ Supports schema versioning| | **Custom implementation for operations** | ✅ can customize details of CRUDL| ❌ falls back on dynamic resource controllers | -Based on the above differences, *we choose Radius.Core/recipePacks to be provisioned imperatively by Applications RP as a first class Radius resource*. The main reason for this decision is that Radius Core resources such as enviroments and recipe-packs could have complex and custom deletion logic compared to what a dynamic resource deletion does. For instance, we need a cascase of deletion when an environment is deleted, or we might want to restrict deleting a recipe pack that is referenced in one or more environment. It is important to support robust core management operations of these resources where as the versioning can follow once Radius versioning support is available. +Based on the above differences, *we choose Radius.Core/recipePacks to be provisioned imperatively by Applications RP as a first class Radius resource*. The main reason for this decision is that Radius Core resources such as enviroments and recipe-packs could have complex and custom deletion logic compared to what a dynamic resource deletion does. For instance, we need a cascade of deletion when an environment is deleted, or we might want to restrict deleting a recipe pack that is referenced in one or more environment. It is important to support robust core management operations of these resources where as the versioning of the type can follow once Radius versioning support is available. -We should make sure the rad resource-type commands cannot alter the schema of these types as part of schema validation (this namespace is reserved for Radius's use). +We should make sure the rad resource-type commands cannot alter the schema of these types as part of schema validation (this namespace is reserved for Radius's use). Appropriate error message should be provided to the user. @@ -231,13 +232,16 @@ interface RecipePacks { >; } ``` +* As an enhancement that can fast follow, we would add a version attribute so that users can version their recipe packs. We could chose name+version as the internal name which would be used to construct recipe pack's resource id. * We choose a map of resource types to their recipe configurations so that the relevant recipe for a type can be easily accessed. * We will not be supporting named recipes going forward as documented in [RRT feature spec](https://github.com/willtsai/design-notes-radius/blob/f9c98baf515263c27e7637131d7a48ae5a01b2c0/features/2025-02-user-defined-resource-type-feature-spec.md#user-story-7--registering-recipes). Therefore the `RecipeDefinition` model does not include a name. -* The operations are all Synchronous, since Recipe Pack is a lightweight configuration resource. - +* we are not supporting "scheme" (http|https|...). We can use the information in recipe location to determine that. We might have to introduce it back if we support other kinds of location for recipes in future. + +* The operations are all Synchronous, since Recipe Pack is a lightweight configuration resource unless we choose to validate the recipe location. +In this case we might want to store the md5 of the recipe too, so that the content could be fetched and the md5 matched. #### Examples @@ -516,18 +520,23 @@ resource computeRecipePack 'Radius.Core/recipePacks@2025-05-01-preview' = { rad deploy computeRecipePack.bicep ``` -Note: rad recipe-pack create command could be added in future. For now, we are using rad deploy to create recipe packs. +The deploy operation should fail if the recipepack already exists AND there is atleast one resource deployed using the recipe pack, unless we are updating the pack to incrementally adding another type to the recipe pack. + +If there is an edit to any of the recipe attributes (recipeKind/recipeLocation/parameters), For now, we should return error mentioning a new recipe pack should be created, but once we have the version support, we should provide error message indicating such changes should happen in a newer version of recipe. + +Note: rad recipe-pack create command could be added as a fast follow feature. For now, we are using rad deploy to create recipe packs. + -2. Show recipe pack details: +1. Show recipe pack details: ``` -$ rad recipe-pack show computeRecipePack +$ rad recipe-pack show computeRecipePack............................................ RESOURCE TYPE GROUP STATE computeRecipePack Radius.Core/recipePacks default Succeeded -RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION -Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 +RESOURCE TYPE RECIPE KIND RECIPE LOCATION RECIPE PARAMETERS +Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 allowPlatformOptions(bool) Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 ``` @@ -535,16 +544,32 @@ Radius.Storage/volumes terraform https://git 3. List recipe packs: ``` -$ rad recipe-pack list [optionally -e myenv] +$ rad recipe-pack list [-g mygroup] + +Lists all recipe packs in all scopes. RESOURCE TYPE GROUP STATE computeRecipePack Radius.Core/recipePacks default Succeeded dataRecipePack Radius.Core/recipePacks default Succeeded ``` -If no -e is specified, this command should list all recipe packs in current scope. +if -g is provided, list recipe packs in that scope. -4. Delete recipe pack: +4. Show environment + +``` +$ rad environment show my-env +RESOURCE TYPE GROUP STATE +my-env Radius.Core/environments default Succeeded + +RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION RECIPE PARAMETERS +computeRecipePack Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48. myparameter(int) +computeRecipePack Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 +computeRecipePack Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 +dataRecipePack Radius.Data/redisCaches terraform https://github.com/project-radius/resource-types-contrib.git//recipes/data/redisCaches?ref=v0.48 +``` + +1. Delete recipe pack: ``` $ rad recipe-pack delete @@ -552,16 +577,27 @@ $ rad recipe-pack delete We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. -5. Register recipe pack to environment: +1. Create an Environment with a Recipe Pack: ``` -$ rad env register recipe-pack recipe-pack-name [-g group-id] +$ rad environment create myEnv +If Recipe Packs is not specified when creating the Environment, the `rad environment create` command sets default Recipe Packs (the same behavior as `rad init`). + +$ rad environment create myEnv \ + --recipe-packs computeRecipePack +This command creates an environment with the `recipePacks[]` property populated with `computeRecipePack`. + +$ rad environment update myEnv \ + --recipe-packs computeRecipePack +The command should use the resource ID to identify the environment is `Radius.Core\environment` resource and only then allow the `recipePack` property to be updated. If the namespace is `Applications.Core`, an error is provided. + +$ rad environment update myEnv \ + --recipe-packs otherResourceGroup/computeRecipePack +If the Recipe Pack is in a different Resource Group than the Environment, the Resource Group is passed as a prefix to the Recipe Pack name. ``` -The command should use the resource ID to identify the environment is `Radius.Core\environment` resource and only then allow recipe pack registration. If the namespace is `Applications.Core`, it should work as it does today. -We specify group resource id if the recipe-pack is in a different scope from the environment. -6. Show environment details: +1. Show environment details: Based on whether the environment namespace is Applications.Core or Radius.Core, the outputs differ. Eventually Applications.Core support will be removed. @@ -610,7 +646,7 @@ The default environment created is initialized with a "recipe pack" which is a b We are choosing to keep the same behavior. But behind the scenes rad init would create a recipe pack resource, with recipe links we use today to construct recipe properties and add this recipe pack's resource id to the environment. -Providing an option for az/aws based recipe packs requires considerable work and would be a future follow up to the feature. +Providing an option to initialize Radius for az/aws based recipe packs requires considerable work and would be a future follow up to the feature. At a high level, that feature would require the users to be able to specify a location to yaml definition for recipe-packs at the time of init and then construct the recipe-pack resource based on that. ### Graph support @@ -620,6 +656,12 @@ Recipe packs will be displayed in application graphs as first-class resources wi Standard logging and tracing will be implemented for all recipe pack operations through the existing Applications RP logging/tracing infrastructure. + +### Community + +Recipe Packs would be authored and shared across community through resource-types-contrib repo. + + ### Breaking changes * Once we support recipe packs, the Radius.Core environments will allow only registration of recipe-packs and not a single recipe. Applications.Core environments will continue to work as it does today and support recipe registration but will be deprecated over time allowing transition time for customers to move from recipes to recipe packs. From 51824d828604663b93ce73ab6aa98cf3a77847b8 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 17 Sep 2025 10:12:45 -0700 Subject: [PATCH 14/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index bb65dda1..ff599b08 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -703,8 +703,8 @@ We could also explore providing some tools to create the new environment resourc - rad init today says installing a "recipe-pack" - might need changes here to enable choosing a pack. (retain behavior) - rad init / install must be updated to create the recipe pack resource type ( as part of registering manifests logic we have today) - if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. (in future) -- would environment and recipe pack ever have different rbac? should we "allow" recipepack is in different radius resource grpup from that of environment? (yes , with -g) -- - prereq: finalize new environment design +- would environment and recipe pack ever have different rbac? should we "allow" recipepack is in different radius resource grpup from that of environment? (yes , with -g, consider 2 diff env owned by 2 diff team) +- prereq: finalize new environment design - handling recipe-packs with dup recipes. at the time of creation, of recipe pack, it could have dups with another recipe-pack. But we have to dtect dups at the time of registering to env. - we are moving away from named recipes. If a customer wishes to use same env for two applications, these application teams have their own recipes, then would we advice them to create 2 enviroments ? We could also guide them to a naming like contoso-recipe-pack and cool-prod-recipe-pack. But this would either require us to allow for duplicate recipes between packs, or require multiple teams to coordinate and ensure their types are different? (its is upto the teams to decide how they want to organize) - now that the "unit" of importing recipes is recipe pack, would we "contrib" recipe pack manifests? (yes) From 9f82f3b7e534187db580b6f42084580f48969697 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 17 Sep 2025 10:59:04 -0700 Subject: [PATCH 15/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index ff599b08..785b10dd 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -577,6 +577,8 @@ $ rad recipe-pack delete We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. +Environment commands related to recipe packs are: + 1. Create an Environment with a Recipe Pack: ``` From cae0e9159d82e9391f564b1af9704b386cd370f8 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 1 Oct 2025 11:02:06 -0700 Subject: [PATCH 16/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 197 +++++++++++++++++++++++---------- 1 file changed, 136 insertions(+), 61 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 785b10dd..3c7ede9e 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -39,9 +39,9 @@ Recipe Packs would bundle together "recipes" as we understand them today. We do As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. This can be error prone when there are many recipes and environments. Radius should provide a way to bulk register (and manage) recipes. -#### Registering recipes to multiple environments +#### Registering the same set of recipes to multiple environments -As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. I have 100s of environments which mostly use the same recipes. Piecing the same recipes together for each environment feels like rework. +As an operator I am responsible for creating Radius Environments using which developers can deploy their applications. As part of creating the environment, I manually link recipes one by one using `rad recipe register` or by updating the environment definition. I have 100s of environments which mostly use the same recipes. Piecing the same recipes together for each environment feels like rework. Radius should provide a way to avoid this rework. #### Sharing Recipe Packs Across Environments and Organizations @@ -135,10 +135,11 @@ Pros: Cons: -- For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could cache the list and construct an in-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. +- For each provisioning of resource, we make a call to registry to fetch the list to check if the recipe is available, and then a call to the specified recipe location to fetch it. We could fetch the list and construct an in-memory recipe pack ephemeral object. But we still do not get the benefits of recipe pack as a first-class resource type. ### High level flow +Radius.Core/recipePacks will be provisioned imperatively by Applications RP. At a very high level, this design approach needs the below steps: @@ -155,51 +156,61 @@ At a very high level, this design approach needs the below steps: As part of supporting Recipe Pack as a resource type, at a high-level, we define a recipePacks.tsp ```tsp -namespace Radius.Core; - -@doc("The recipe pack resource") -model RecipePackResource - is TrackedResourceRequired { - @doc("recipe pack name") - @key("recipePackName") - @path - @segment("recipePacks") - name: ResourceNameString; -} +namespace Applications.Core; + +@doc("The recipe pack resource") +model RecipePackResource +is TrackedResourceRequired { +@doc("recipe pack name") +@key("recipePackName") +@path +@segment("recipePacks") +name: ResourceNameString; +} -@doc("Recipe Pack properties") -model RecipePackProperties { - @doc("The status of the asynchronous operation.") - @visibility("read") - provisioningState?: ProvisioningState; +@doc("Recipe Pack properties") +model RecipePackProperties { +@doc("The status of the asynchronous operation.") +@visibility("read") +provisioningState?: ProvisioningState; - @doc("Description of what this recipe pack provides") - description?: string; +@doc("Description of what this recipe pack provides") +description?: string; - @doc("Map of resource types to their recipe configurations") - recipes: Record; -} +@doc("Version of the recipe pack") +version: string; -@doc("Recipe definition for a specific resource type") -model RecipeDefinition { - @doc("The type of recipe (e.g., terraform, bicep)") - recipeKind: RecipeKind; +@doc("List of environment IDs that reference this recipe pack") +@visibility("read") +referencedBy?: string[]; - @doc("URL or path to the recipe source") - recipeLocation: string; +@doc("Map of resource types to their recipe configurations") +recipes: Record; +} - @doc("Parameters to pass to the recipe") - parameters?: {}; -} +@doc("Recipe definition for a specific resource type") +model RecipeDefinition { +@doc("The type of recipe (e.g., terraform, bicep)") +recipeKind: RecipeKind; -@doc("The type of recipe") -enum RecipeKind { - @doc("Terraform recipe") - terraform: "terraform", +@doc("URL or path to the recipe source") +recipeLocation: string; - @doc("Bicep recipe") - bicep: "bicep", -} +@doc("recipe digest in the format algorithm:digest_value") +recipeDigest?: string; + +@doc("Parameters to pass to the recipe") +parameters?: {}; +} + +@doc("The type of recipe") +enum RecipeKind { +@doc("Terraform recipe") +terraform: "terraform", + +@doc("Bicep recipe") +bicep: "bicep", +} @armResourceOperations interface RecipePacks { @@ -232,16 +243,21 @@ interface RecipePacks { >; } ``` -* As an enhancement that can fast follow, we would add a version attribute so that users can version their recipe packs. We could chose name+version as the internal name which would be used to construct recipe pack's resource id. + +* We add a version attribute so that users can version their recipe packs. We could chose name+version as the internal name which would be used to construct recipe pack's resource id. * We choose a map of resource types to their recipe configurations so that the relevant recipe for a type can be easily accessed. * We will not be supporting named recipes going forward as documented in [RRT feature spec](https://github.com/willtsai/design-notes-radius/blob/f9c98baf515263c27e7637131d7a48ae5a01b2c0/features/2025-02-user-defined-resource-type-feature-spec.md#user-story-7--registering-recipes). Therefore the `RecipeDefinition` model does not include a name. -* we are not supporting "scheme" (http|https|...). We can use the information in recipe location to determine that. We might have to introduce it back if we support other kinds of location for recipes in future. +* we are not supporting "scheme" (http|https|...). We can use the information in recipe location to determine that. We might have to introduce it back if we support other kinds of location for recipes in future.We might also have to introduce it for functional tests. + +* The operations are all Synchronous, since Recipe Pack is a lightweight configuration resource. -* The operations are all Synchronous, since Recipe Pack is a lightweight configuration resource unless we choose to validate the recipe location. -In this case we might want to store the md5 of the recipe too, so that the content could be fetched and the md5 matched. +* We maintain a reverse index into environment IDs so that we can handle CRUDL operations gracefully. For example, only a recipe pack that is not referenced by any environment can be deleted or updated. + +* We allow the users tp input a digest for a recipe to enhance security. More about this in [Verifying Recipy Integrity](#security) + #### Examples @@ -257,6 +273,7 @@ resource computeRecipePack 'Radius.Core/recipePacks@2026-01-01-preview' = { 'Radius.Compute/containers': { recipeKind: 'terraform' recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' + recipeDigest: 'sha256:4g5h6i7j8k9l0m1n2o3p4q5r6s7t8u9v0w1x2y3z4a5b6c7d8e9f0g1h2i3j4k5' parameters: { allowPlatformOptions: true anIntegerParam: 1 @@ -474,7 +491,8 @@ As part of Radius.Core/environments design/implementation below points should be In Dynamic RP, while deploying a dynamic resource: 1. Add support to look up the `Radius.Core/environments` that is in use, fetch environment's recipe-pack ids -2. Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. +2. Go over the recipe packs registered in environment one by one until the first recipe pack holding the recipe for the resource type of interest is found. This is because, by design we dont allow duplicate recipes for a resource type either in one recipe pack or across recipe packs in on eenvironment. + 3. Use the recipe information just fetched and construct recipe details that can be passed to the existing recipe engine mechanism. Since Dynamic RP shares the recipe engine code with Applications RP, Dynamic Resources should be able to avail recipe packs once Applications RP code changes are complete. @@ -562,11 +580,9 @@ $ rad environment show my-env RESOURCE TYPE GROUP STATE my-env Radius.Core/environments default Succeeded -RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION RECIPE PARAMETERS -computeRecipePack Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48. myparameter(int) -computeRecipePack Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 -computeRecipePack Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 -dataRecipePack Radius.Data/redisCaches terraform https://github.com/project-radius/resource-types-contrib.git//recipes/data/redisCaches?ref=v0.48 +RECIPE PACKS +computeRecipePack +dataRecipePack ``` 1. Delete recipe pack: @@ -608,11 +624,9 @@ $ rad environment show my-env RESOURCE TYPE GROUP STATE my-env Radius.Core/environments default Succeeded -RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION -computeRecipePack Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 -computeRecipePack Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 -computeRecipePack Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 -dataRecipePack Radius.Data/redisCaches terraform https://github.com/project-radius/resource-types-contrib.git//recipes/data/redisCaches?ref=v0.48 +RECIPE PACK +computeRecipePack +dataRecipePack ``` 7. List recipes in environment: @@ -652,7 +666,7 @@ Providing an option to initialize Radius for az/aws based recipe packs requires ### Graph support -Recipe packs will be displayed in application graphs as first-class resources with their own lifecycle and relationships to environments. +Recipe packs will not be displayed in application graphs since the are operatiors concept and not part of an application as a component. ### Logging/Tracing support @@ -676,23 +690,84 @@ We could also explore providing some tools to create the new environment resourc ## Test plan -[To be completed] +* Add E2E to deploy application using recipe packs. +* As part of cleanup, all tests should migrate from Application.Core/ environment and recipes to Radius.Core/recipePacks ## Security -[To be completed] +**Current Security Posture** + +Today, Radius provides different levels of security for recipe integrity: + +- **Bicep recipes**: When using tags (e.g., `latest`), Radius fetches the digest of the specified tag from the repository, then downloads the image using that digest. If the image is tampered with but the digest remains unchanged, the download will fail. + +- **Terraform recipes**: Currently have no integrity verification checks. + +**Security Gaps** + +The current approach still has vulnerabilities: +- An attacker who replaces both the image and its digest +- Registry compromises where the image points to malicious content or gets redirected to a malicious server + +**Proposed Solution: Recipe Digests** + +To address these security gaps, Recipe Packs will support an optional `recipeDigest` field for each recipe. This enhancement provides: + +1. **User-specified digests**: Operators can input a known-good digest when creating a Recipe Pack +2. **Engine-level verification**: Both Bicep and Terraform engines will be enhanced to validate recipes against the provided digest before execution +3. **Comprehensive coverage**: Since most Radius resource types will be provisioned through Recipe Packs, this feature addresses security concerns across the platform + +**Integration with Dependency Management** + +For teams using dependency management tools: +- **Dependabot integration**: When app definitions specify digests directly, Dependabot can automatically update hashes in IaC when newer images are available +- **Automated workflows**: After merge, `rad deploy` fetches updated recipes using the new digests +- **No double specification**: When digests are already specified in application code, operators don't need to duplicate them in Recipe Packs. Therefore, the "digest" attribute is optional while creating the recipe pack. ## Compatibility (optional) -[To be completed] +Users should migrate from Applications.Core to Radius.Core namespace to make use of new environments and recipePacks resources. +We will allow both namespac to coexist until a point where it would be safe to remove the support for Applications.Core. ## Monitoring -[To be completed] +Logs and Traces should automatically capture most metrics. +We might want to add metrics related to recipe pack usage. ## Development plan + +#### Phase 1: Introduce Radius.Core namespace and setup routing +- UCP changes to route Radius.Core resources to Applications RP +- Applications RP changes to add new namespace +- Add a manifest to register the new namecpase and types + +#### Resource Schema +- Define `Radius.Core/recipePacks` schema +- Add convertors and basic controllers + +#### Phase 2: Versioning +- Handle `version` field to `recipePack` +- Update recipe pack CRUDL APIs to handle versions correctly + +#### Phase 3: Recipe Engine support +- Add support to recipe engine to deploy an application using recipe packs +- Add E2E to deploy an app using recipe packs. + + +#### Phase 4: CLI & Bicep Support +- CLI: `rad recipe-pack register | list | show | delete`. +- Bicep: Add `Applications.Core/recipePacks` resource type. +- Support referencing packs by name and version. + + +#### Phase 5: Digest Support +- Add support in recipe engiens to validate recipe integrity using registered hashes. + +### Phase 6: Documentation & Samples +- Author guide for pack creation and usage. +- Provide sample packs and migration docs. +- Update todo app to display recipe packs in Use. -1. ## Open issues From 60e18cc89614b0be6b1dbd3cd2426e6441ff7bf8 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 1 Oct 2025 11:14:32 -0700 Subject: [PATCH 17/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 3c7ede9e..7af3cdc1 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -771,7 +771,7 @@ We might want to add metrics related to recipe pack usage. ## Open issues -[To be completed] +https://dev.azure.com/azure-octo/Incubations/_workitems/edit/17257 should be a follow up to the feature. Named packs could offer a potential solution. ## notes/questions for myself (to be deleted before merging) From 0e1ca07467863f33a7313051bba1ee32a7e08837 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 1 Oct 2025 11:38:07 -0700 Subject: [PATCH 18/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 7af3cdc1..e29e04b6 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -719,7 +719,7 @@ To address these security gaps, Recipe Packs will support an optional `recipeDig **Integration with Dependency Management** -For teams using dependency management tools: +For teams using dependency management tools to keep their IaC updated: - **Dependabot integration**: When app definitions specify digests directly, Dependabot can automatically update hashes in IaC when newer images are available - **Automated workflows**: After merge, `rad deploy` fetches updated recipes using the new digests - **No double specification**: When digests are already specified in application code, operators don't need to duplicate them in Recipe Packs. Therefore, the "digest" attribute is optional while creating the recipe pack. From b90983506c2d603d4a12ba7b775448926ae80867 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Wed, 1 Oct 2025 11:39:34 -0700 Subject: [PATCH 19/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index e29e04b6..f779ab1c 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -720,7 +720,7 @@ To address these security gaps, Recipe Packs will support an optional `recipeDig **Integration with Dependency Management** For teams using dependency management tools to keep their IaC updated: -- **Dependabot integration**: When app definitions specify digests directly, Dependabot can automatically update hashes in IaC when newer images are available +- **Dependabot integration**: When app definitions specify digests directly, Dependabot can automatically update hashes in IaC when newer images are available (Ref: https://eng.ms/docs/products/dependabot/automatic-container-updates.) - **Automated workflows**: After merge, `rad deploy` fetches updated recipes using the new digests - **No double specification**: When digests are already specified in application code, operators don't need to duplicate them in Recipe Packs. Therefore, the "digest" attribute is optional while creating the recipe pack. From 275005b3af657e3334291102321e3476aa4e910e Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Thu, 23 Oct 2025 14:42:23 -0700 Subject: [PATCH 20/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 43 ++++++++++------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index f779ab1c..4bdbac86 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -76,8 +76,6 @@ Based on the above differences, *we choose Radius.Core/recipePacks to be provisi We should make sure the rad resource-type commands cannot alter the schema of these types as part of schema validation (this namespace is reserved for Radius's use). Appropriate error message should be provided to the user. - - ### Other alternatives considered ***Embed all recipe mappings inline in the Environment*** @@ -177,8 +175,6 @@ provisioningState?: ProvisioningState; @doc("Description of what this recipe pack provides") description?: string; -@doc("Version of the recipe pack") -version: string; @doc("List of environment IDs that reference this recipe pack") @visibility("read") @@ -193,14 +189,17 @@ model RecipeDefinition { @doc("The type of recipe (e.g., terraform, bicep)") recipeKind: RecipeKind; +@doc("Connect to the location using HTTP (not HTTPS). This should be used when the location is known not to support HTTPS, for example in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS)") +plainHttp?: boolean; + @doc("URL or path to the recipe source") recipeLocation: string; @doc("recipe digest in the format algorithm:digest_value") recipeDigest?: string; -@doc("Parameters to pass to the recipe") -parameters?: {}; +@doc("Parameters to pass to the recipe") +parameters?: Record; } @doc("The type of recipe") @@ -374,7 +373,7 @@ CREATE response: "lastModifiedByType": "" }, "tags": {}, - "type": "Applications.Core/recipePacks" + "type": "Radius.Core/recipePacks" } ``` @@ -423,7 +422,7 @@ READ response: "lastModifiedByType": "" }, "tags": {}, - "type": "Applications.Core/recipePacks" + "type": "Radius.Core/recipePacks" } ``` @@ -538,9 +537,7 @@ resource computeRecipePack 'Radius.Core/recipePacks@2025-05-01-preview' = { rad deploy computeRecipePack.bicep ``` -The deploy operation should fail if the recipepack already exists AND there is atleast one resource deployed using the recipe pack, unless we are updating the pack to incrementally adding another type to the recipe pack. - -If there is an edit to any of the recipe attributes (recipeKind/recipeLocation/parameters), For now, we should return error mentioning a new recipe pack should be created, but once we have the version support, we should provide error message indicating such changes should happen in a newer version of recipe. +The deploy operation should succeed even if the recipepack already exists and is referenced by environments(update supported). This is in parity with the current recipe behavior we have. Note: rad recipe-pack create command could be added as a fast follow feature. For now, we are using rad deploy to create recipe packs. @@ -550,8 +547,8 @@ Note: rad recipe-pack create command could be added as a fast follow feature. Fo ``` $ rad recipe-pack show computeRecipePack............................................ -RESOURCE TYPE GROUP STATE -computeRecipePack Radius.Core/recipePacks default Succeeded +RESOURCE TYPE GROUP +computeRecipePack Radius.Core/recipePacks default RESOURCE TYPE RECIPE KIND RECIPE LOCATION RECIPE PARAMETERS Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 allowPlatformOptions(bool) @@ -591,7 +588,7 @@ dataRecipePack $ rad recipe-pack delete ``` -We could delete recipe-packs that are not referenced by any environment in any resource-group. This requires further thought and is similar to deletion of resources such as resource-type resource we have today. +We could delete recipe-packs that are not referenced by any environment in any resource-group. If referenced by envrinmonts, the delete should also update the environment to not have the recipepack ID in its list of recipe packs. Allowance of recipe pack deletion when there are resources refering to it is in parity with today's recipe behavior. Environment commands related to recipe packs are: @@ -633,7 +630,7 @@ dataRecipePack ``` $ rad recipe list -environment my-env -RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE VERSION RECIPE LOCATION +RECIPE PACK RESOURCE TYPE RECIPE KIND RECIPE LOCATION computeRecipePack Radius.Compute/containers terraform https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48 computeRecipePack Radius.Security/secrets terraform https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets?ref=v0.48 computeRecipePack Radius.Storage/volumes terraform https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes?ref=v0.48 @@ -667,12 +664,12 @@ Providing an option to initialize Radius for az/aws based recipe packs requires ### Graph support Recipe packs will not be displayed in application graphs since the are operatiors concept and not part of an application as a component. +However, dashboard will be enhanced to show a list of recipe packs, similar to the environment list we have today. ### Logging/Tracing support Standard logging and tracing will be implemented for all recipe pack operations through the existing Applications RP logging/tracing infrastructure. - ### Community Recipe Packs would be authored and shared across community through resource-types-contrib repo. @@ -774,17 +771,3 @@ We might want to add metrics related to recipe pack usage. https://dev.azure.com/azure-octo/Incubations/_workitems/edit/17257 should be a follow up to the feature. Named packs could offer a potential solution. -## notes/questions for myself (to be deleted before merging) - -- recipe-pack : RRT or NOT? same question as RRT in the Radius.Config namespace (app, env). These types are not meant to be edited by users, and should be as defined by Radius so that Radius can work. (imperatative) -- rad init today says installing a "recipe-pack" - might need changes here to enable choosing a pack. (retain behavior) -- rad init / install must be updated to create the recipe pack resource type ( as part of registering manifests logic we have today) -- if we want the ability to "init" with a selected pack say for az, how would we do it? it might help to allow url to recipe-pack manifest, and as part of rad init , create the rrt as well as the rrt resource (using the url for yaml manifest) and init the env with it. (in future) -- would environment and recipe pack ever have different rbac? should we "allow" recipepack is in different radius resource grpup from that of environment? (yes , with -g, consider 2 diff env owned by 2 diff team) -- prereq: finalize new environment design -- handling recipe-packs with dup recipes. at the time of creation, of recipe pack, it could have dups with another recipe-pack. But we have to dtect dups at the time of registering to env. -- we are moving away from named recipes. If a customer wishes to use same env for two applications, these application teams have their own recipes, then would we advice them to create 2 enviroments ? We could also guide them to a naming like contoso-recipe-pack and cool-prod-recipe-pack. But this would either require us to allow for duplicate recipes between packs, or require multiple teams to coordinate and ensure their types are different? (its is upto the teams to decide how they want to organize) -- now that the "unit" of importing recipes is recipe pack, would we "contrib" recipe pack manifests? (yes) -- would we think about enforcing a size limit on recipe pack? how many recipes it can have ? (not now) -- - should recipe-pack resource have a list of env ids to which it belongs? typically, RRTs have an app id or env id. (no, causes a cycle) -- - cli -support versus deploying through bicep (create cmd can come later for recipe pack) \ No newline at end of file From 3700ae8102deb78a95766264e0fbe30e79754927 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Thu, 23 Oct 2025 15:24:52 -0700 Subject: [PATCH 21/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 40 ++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 4bdbac86..2b1a9d19 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -12,22 +12,36 @@ This document proposes the design of a Recipe Pack as a first class resource typ ## Terms and definitions -| Term | Definition | -| ----------- | -------------------------------------------------------------------------------------------------- | -| Recipe | IaC templates that operators register on a Radius Environment | -| Recipe Pack | A collection of recipes that can be managed as an entity | -| RRT | [Radius Resource Type](https://docs.radapp.io/guides/author-apps/custom/overview/) | +| Term | Definition | +| ----------------------- | -------------------------------------------------------------------------------------------------- | +| Recipe | IaC templates that operators register on a Radius Environment | +| Recipe Pack | A collection of recipes that can be managed as an entity | +| RRT | [Radius Resource Type](https://docs.radapp.io/guides/author-apps/custom/overview/) | +| Applications RP | Applications Resource Provider - manages Radius application resources and recipe operations | +| Dynamic RP | Dynamic Resource Provider - handles user-defined resource types and their provisioning | +| UCP | Universal Control Plane - routes resource operations to appropriate resource providers | +| IaC | Infrastructure as Code - declarative configuration files for managing infrastructure | +| Recipe Digest | Cryptographic hash (e.g., SHA-256) used to verify the integrity of a recipe's content | +| Recipe Parameters | Configuration values passed to recipes during resource provisioning | +| Resource Type | Identifier that defines the type of resource (e.g., `Radius.Compute/containers`) | +| Environment | Radius resource that defines the deployment context and available recipes for applications | +| Namespace | Logical grouping of resource types (e.g., `Applications.Core`, `Radius.Core`) | +| Recipe Engine | Component responsible for executing recipes during resource provisioning | +| Portable Resource | Radius resource that can be deployed across different cloud platforms using recipes | ## Objectives -> **Issue Reference:** +[**Recipe Packs**](https://github.com/radius-project/roadmap/issues/9) ### Goals -Provide Recipe Packs as a Radius feature to bundle multiple recipes as a single manageable entity into a Radius Environment (e.g., a pack for ACI that includes all necessary recipes). - - - Radius should provide APIs to manage Radius.Core/recipePacks resource through CRUDL operations - +- Introduce Recipe Packs as a first-class resource type (`Radius.Core/recipePacks`) managed imperatively by Applications RP +- Enable bundling multiple recipes for different resource types into reusable units that can be referenced by environments +- Provide APIs for CRUDL (Create, Read, Update, Delete, List) operations on Recipe Pack resources +- Support bulk registration of recipes to environments, reducing manual effort and errors when managing many recipes across multiple environments +- Enhance recipe security by supporting optional digest verification for both Bicep and Terraform recipes +- Provide CLI commands (`rad recipe-pack`) for managing Recipe Packs +- Provide Dashboard view for recipe packs. ### Non goals @@ -255,10 +269,8 @@ interface RecipePacks { * We maintain a reverse index into environment IDs so that we can handle CRUDL operations gracefully. For example, only a recipe pack that is not referenced by any environment can be deleted or updated. -* We allow the users tp input a digest for a recipe to enhance security. More about this in [Verifying Recipy Integrity](#security) - - - +* We allow the users to input a digest for a recipe to enhance security. More about this in [Verifying Recipy Integrity](#security) + #### Examples Below is a sample bicep definition of a recipe pack resource: From 0e08ecd3714e3ad84e0f5abf81b7309f2392bc45 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Thu, 23 Oct 2025 15:29:01 -0700 Subject: [PATCH 22/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 2b1a9d19..3340a468 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -557,7 +557,7 @@ Note: rad recipe-pack create command could be added as a fast follow feature. Fo 1. Show recipe pack details: ``` -$ rad recipe-pack show computeRecipePack............................................ +$ rad recipe-pack show computeRecipePack RESOURCE TYPE GROUP computeRecipePack Radius.Core/recipePacks default @@ -594,7 +594,7 @@ computeRecipePack dataRecipePack ``` -1. Delete recipe pack: +5. Delete recipe pack: ``` $ rad recipe-pack delete @@ -602,6 +602,8 @@ $ rad recipe-pack delete We could delete recipe-packs that are not referenced by any environment in any resource-group. If referenced by envrinmonts, the delete should also update the environment to not have the recipepack ID in its list of recipe packs. Allowance of recipe pack deletion when there are resources refering to it is in parity with today's recipe behavior. +By default, dlete looks for rcipe-pack in current group. It should take in optional scope to delete recipe packs in Other scope. + Environment commands related to recipe packs are: 1. Create an Environment with a Recipe Pack: @@ -780,6 +782,8 @@ We might want to add metrics related to recipe pack usage. ## Open issues -https://dev.azure.com/azure-octo/Incubations/_workitems/edit/17257 should be a follow up to the feature. Named packs could offer a potential solution. +- Revisit recipe precedence decision. +- Versioning support on recipe/ recipe-packs. + From dddc17b49761997e002bf0c92204fbf63517cb44 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Thu, 23 Oct 2025 15:30:08 -0700 Subject: [PATCH 23/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 3340a468..7a38caae 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -600,7 +600,7 @@ dataRecipePack $ rad recipe-pack delete ``` -We could delete recipe-packs that are not referenced by any environment in any resource-group. If referenced by envrinmonts, the delete should also update the environment to not have the recipepack ID in its list of recipe packs. Allowance of recipe pack deletion when there are resources refering to it is in parity with today's recipe behavior. +We could delete recipe-packs that are not referenced by any environment in any resource-group. If referenced by environments, the delete should also update the environment to not have the recipepack ID in its list of recipe packs. Allowance of recipe pack deletion when there are resources refering to it is in parity with today's recipe behavior. By default, dlete looks for rcipe-pack in current group. It should take in optional scope to delete recipe packs in Other scope. From 210590a7182f78d851bf831feaf7e2930179eef1 Mon Sep 17 00:00:00 2001 From: nithyatsu Date: Thu, 23 Oct 2025 15:47:29 -0700 Subject: [PATCH 24/24] wip Signed-off-by: nithyatsu --- recipe/2025-08-recipe-packs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/2025-08-recipe-packs.md b/recipe/2025-08-recipe-packs.md index 7a38caae..b74917b7 100644 --- a/recipe/2025-08-recipe-packs.md +++ b/recipe/2025-08-recipe-packs.md @@ -602,7 +602,7 @@ $ rad recipe-pack delete We could delete recipe-packs that are not referenced by any environment in any resource-group. If referenced by environments, the delete should also update the environment to not have the recipepack ID in its list of recipe packs. Allowance of recipe pack deletion when there are resources refering to it is in parity with today's recipe behavior. -By default, dlete looks for rcipe-pack in current group. It should take in optional scope to delete recipe packs in Other scope. +By default, delete looks for recipe-pack in current group. It should take in optional scope to delete recipe packs in Other scope. Environment commands related to recipe packs are: