Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

End-to-end UDT feature spec #81

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

zachcasper
Copy link
Contributor

@zachcasper zachcasper requested review from a team as code owners February 10, 2025 22:28
Signed-off-by: Zach Casper <[email protected]>
Copy link
Member

@brooke-hamilton brooke-hamilton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: typo: ingress

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very cool

…roviders, renamed auto-injected environment variables.

Signed-off-by: Zach Casper <[email protected]>
}
}
+ // Specifying required properties
+ required: ['size']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be included within the property declaration:

size: {
          type: 'string'
          enum: ['S', 'M', 'L', 'XL']
          required: true
          ...
          }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be better in my mind. I believe @Reshrahim said this was an OpenAPI thing. If we can do what you propose, I prefer that.

Copy link
Contributor

@lakshmimsft lakshmimsft Feb 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, I'll defer to @nithyatsu , @Reshrahim who're familiar with OpenAPI spec.


Almost all applications connect to other systems which are managed independently. These systems could be other applications within the organization or software as a service applications managed by other vendors. These dependencies present challenges in a complex, interconnected organization. The Radius application graph is designed to help managed these dependencies by documenting connections between application components and visualizing them via the Radius dashboard and API. However, today, the application graph only supports connections between Radius-managed components. With user-defined resource types, organizations can represent application dependencies which are external to the application, environment, or organization.

Radius already restricts the ability to create resources which do not have an associated recipe in the target environment. If a resource is created in an environment without a recipe for that resource type, it will fail with an error stating that no recipe was found for the corresponding resource type. Not having a recipe for a resource type in an environment is how the platform engineer controls which resources can be deployed in which environment.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I understand this correctly. We have two types of resource provisioning: recipe and manual. I don't think we need to have a recipe for a specific resource type to have an instance of that resource type in a given environment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true for portable resource types only right? Are you suggesting we reuse the resourceProvisioning: 'manual' property for UDT? If so, that seems like a valid approach to have consistency between the two.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should only be for portable resources but I need to double-check. Not sure which processor the UDT uses but, if it uses the same, then resourceProvisioning is taken into account in that flow.

Copy link
Contributor

@lakshmimsft lakshmimsft Feb 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this (explicit manual declaration) is not needed since UDTs that support recipes will Always be deployed with recipes. Pls confirm.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, I think UDTs that support recipes should also allow manual provisioning too. SupportsRecipes should be an extra capability on top of the default capabilities.

Note: This is just my opinion :)

name: 'twilio'
properties: {
environment: production
connection-string 'https://api.twilio.com/2010-04-01/Accounts/${twilio-account-sid}'
Copy link
Contributor

@nithyatsu nithyatsu Feb 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

connection-string would have the connected-resource-environment-variable attribute too correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, these could have those env var specified here as well.

password: {
type: 'string'
description: 'Password for the external service user'
connected-resource-environment-variable: EXTERNAL_SERVICE_PASSSWORD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
connected-resource-environment-variable: EXTERNAL_SERVICE_PASSSWORD
connected-resource-environment-variable: EXTERNAL_SERVICE_PASSWORD

Comment on lines +680 to +688
resource twilio 'MyCompany.App/externalService@v1alpha1' = {
name: 'twilio'
properties: {
environment: production
connection-string 'https://api.twilio.com/2010-04-01/Accounts/${twilio-account-sid}'
credentials:
username: ${twilio-username}
password: ${twilio-password}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, the resourceProvisioning property gets set to recipe. But you can also set it to manual: https://github.com/radius-project/radius/blob/main/test/testrecipes/test-bicep-recipes/resource-creation.bicep#L14. This is just an example.


When a developer creates a `MyCompany.App/service` resource, they will not need to have any awareness that an Envoy proxy is also created. This abstraction enables the platform engineer to easily inject sidecar containers. Envoy is shown in the example here, but other common sidecars are container security scanning tools such as Aqua Security and observability tools such as OpenTelemetry or Datadog.

The developer will, however, see that Envoy is deployed when they inspect the application graph since the child resources are standard Radius resources and will appear in the application graph.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Radius support child resources as of now? Is there an example Radius Bicep to that?

'''
// If true (default) allow recipes to be registered to deploy resources
// If false, resource can be created in any environment
allowRecipes: false
Copy link
Contributor

@nithyatsu nithyatsu Feb 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

downside here, is that a user cannot switch from production env to qa env and expect to deploy the same bicep and automatically connect to a staging twilio url. Am I understanding this correctly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that? I was imaging the twilio resource residing in both prod and qa environments, but the connection string would be set differently. As long as the resource name twilio is consistent across environments, the application could consume the twilio resources properties.


**Summary**

Almost all applications connect to other systems which are managed independently. These systems could be other applications within the organization or software as a service applications managed by other vendors. These dependencies present challenges in a complex, interconnected organization. The Radius application graph is designed to help managed these dependencies by documenting connections between application components and visualizing them via the Radius dashboard and API. However, today, the application graph only supports connections between Radius-managed components. With user-defined resource types, organizations can represent application dependencies which are external to the application, environment, or organization.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, today, the application graph only supports connections between Radius-managed components. With user-defined resource types, organizations can represent application dependencies which are external to the application, environment, or organization.

Doesn't extender enable this today? Trying to understand the specific scenario in what exists today vs what the second sentence above is proposing.


Radius already restricts the ability to create resources which do not have an associated recipe in the target environment. If a resource is created in an environment without a recipe for that resource type, it will fail with an error stating that no recipe was found for the corresponding resource type. Not having a recipe for a resource type in an environment is how the platform engineer controls which resources can be deployed in which environment.

However, to represent an external resource, Radius will support creating resource types which do not, and cannot, have a recipe registered to it. These recipe-less resource types are only resources within the Radius application graph—there is no deployed resource or other functionality associated with them aside from reading the properties such as reading the name, description, or connection string.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, to represent an external resource, Radius will support creating resource types which do not, and cannot, have a recipe registered to it.

We do support an option to provide resource id or properties of an existing resource deployed outside of Radius. https://docs.radapp.io/reference/resource-schema/databases/mongodb/#provision-manually

These recipe-less resource types are only resources within the Radius application graph—there is no deployed resource or other functionality associated with them aside from reading the properties such as reading the name, description, or connection string.

Is it fair to assume that it will still be defined in the app.bicep file as a UDT?

resource twilio 'MyCompany.App/externalService@v1alpha1' = {
name: 'twilio'
properties: {
environment: production
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
environment: production
environment: environment.id

This property expects a resource id.

}
```

Then the developer can connect to the Twilio resource in their application by using the `existing` keyword.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the expected state of this resource when the application gets deleted?

properties: {
container: {
// Use impage property from the parent resource
image: ${parent.image}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is parent.image defined?

Comment on lines +757 to +765
resource proxy 'Applications.Core/containers@2023-10-01-preview' = {
name: 'proxy'
properties: {
container: {
image: 'envoy:latest'
...
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit confused by bundling of schema (parent resource) with resources that are existing with values specified. It's likely too early to debate on this either way given that we haven't taken yet looked into technical aspects of enabling bicep for resource manifests.

Radius will continue to ship with core resource types including containers, auto-scalers, gateways, volumes, and secrets. It will have built-in logic for deploying these resources to various container platforms including Kubernetes, ECS, ACA, ACI, and CloudRun. In order to allow the creation of more abstract, application-oriented resource types, user-defined resource types will support the concept of child resources.

Child resources are resources which get deployed when its parent resource is deployed. The lifecycle of the child resource is tied to that of the parent. These child resources can be a mix of core resource types and user-defined resource types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will support one layer of child resources going ahead. do we anticipate further nesting? children of children??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect one layer of children within a single resource type definition. But that child could have another child within its definition. So syntactically, one level of children, but logically, many. But the that multi-layer nesting would be in the future. Single layer is all that's needed in the beginning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.