From b7a5ed9173a5851c2f8ce0892bd08520005187cc Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Fri, 12 Sep 2025 12:40:52 +0200 Subject: [PATCH 01/39] Added recipe for MySQL database Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 36 +++++ Data/mySqlDatabases/mySqlDatabases.yaml | 79 ++++++++++ .../kubernetes/bicep/kubernetes-mySql.bicep | 138 ++++++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 Data/mySqlDatabases/README.md create mode 100644 Data/mySqlDatabases/mySqlDatabases.yaml create mode 100644 Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md new file mode 100644 index 00000000..5d93d6ff --- /dev/null +++ b/Data/mySqlDatabases/README.md @@ -0,0 +1,36 @@ +# Radius.Data/mySqlDatabases + +## Overview + +The **Radius.Data/mySqlDatabases** resource type represents a MySQL database. It allows developers to create and easily connect to a MySQL database as part of their Radius applications. + +Developer documentation is embedded in the resource type definition YAML file, and it is accessible via the `rad resource-type show Radius.Data/mySqlDatabases` command. + +## Recipes + +A list of available Recipes for this resource type, including links to the Bicep and Terraform templates: + +|Platform| IaC Language| Recipe Name | Stage | +|---|---|---|---| +| Kubernetes | Bicep | kubernetes-mySql.bicep | Alpha | + +## Recipe Input Properties + +Properties for the **Radius.Data/mySqlDatabases** resource type are provided via the [Recipe Context](https://docs.radapp.io/reference/context-schema/) object. These properties include: + +- `context.properties.database`(string, optional): The name of the database to create/use. +- `context.properties.user`(string, optional): The username to use to connect to the database. +- `context.properties.tag`(string, optional): The MySQL server version as a container tag. +- `context.properties.memoryRequest`(string, optional): Memory request for the mysql deployment. +- `context.properties.memoryLimit`(string, optional): Memory limit for the mysql deployment. + +## Recipe Output Properties + +The **Radius.Data/mySqlDatabases** resource type expects the following output properties to be set in the Results object in the Recipe: + +- `context.properties.host` (string): The hostname used to connect to the MySQL server. +- `context.properties.port` (integer): The port number used to connect to the MySQL server. +- `context.properties.database` (string): Database name to select on connection. +- `context.properties.user` (string): The username for connecting to the database. +- `context.properties.password` (string): The password for connecting to the database. +- `context.properties.root_password` (string): The password for the MySQL server root user. diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml new file mode 100644 index 00000000..a0a4ab3d --- /dev/null +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -0,0 +1,79 @@ +namespace: Radius.Data +types: + mySqlDatabases: + description: | + The Radius.Data/mySqlDatabases Resource Type deploys a MySQL database. + + To deploy a new MySQL database, add the mySqlDatabases resource to the application definition Bicep file. + + param environment string + resource mySqlDatabase 'Radius.Data/mySQL@2023-10-01-preview' = { + name: 'mySqlDatabase' + properties: { + environment: environment + } + } + + To connect your application to the MySQL database, establish a connection from the container to the database resource as shown below. + + resource myContainer 'Radius.Compute/containers@2025-08-01-preview' = { + name: 'myContainer' + properties: { + environment: environment + application: myApplication.id + containers: { + frontend: { + image: 'frontend:latest' + } + } + connections: { + mySql:{ + source: mySqlDatabase.id + } + } + } + } + apiVersions: + '2023-10-01-preview': + schema: + type: object + properties: + environment: + type: string + description: "(Required) The Radius environmentID. Typically set by the rad CLI." + application: + type: string + description: "(Optional) The application ID which the resource is associated with." + database: + type: string + description: "(Optional) The name of the database." + user: + type: string + description: "(Optional) The username used to authenticate to the database." + password: + type: string + description: "(Read-only) The password used to authenticate to the database." + readOnly: true + host: + type: string + description: "(Read-only) The host name used to connected to the database." + readOnly: true + port: + type: integer + description: "(Read-only) The port number used to connected to the the database." + readOnly: true + root_password: + type: string + description: "(Read-only) The MySQL root password." + readOnly: true + tag: + type: string + description: "(Optional) MySQL server version." + memoryRequest: + type: string + description: "(Optional) Memory request for the MySQL deployment." + memoryLimit: + type: string + description: "(Optional) Memory limit for the MySQL deployment." + required: + - environment \ No newline at end of file diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep new file mode 100644 index 00000000..687e032f --- /dev/null +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep @@ -0,0 +1,138 @@ +@description('Information about what resource is calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.io/reference/context-schema/ ') +param context object + +extension kubernetes with { + kubeConfig: '' + namespace: context.runtime.kubernetes.namespace +} as kubernetes + +@description('Name of the MySQL database. Defaults to the application name.') +param database string = context.application.name + +@description('MySQL username. Defaults to -user') +param user string = '${context.application.name}-user' + +@description('MySQL user password. Defaults to a unique generated value.') +@secure() +param password string = uniqueString(context.resource.id, newGuid()) + +@description('MySQL root user password. Defaults to a unique generated value.') +@secure() +param root_password string = uniqueString(context.resource.id, newGuid()) + +@description('Tag to pull for the mysql container image. Defaults to latest.') +param tag string = 'latest' + +@description('Memory request for the mysql deployment. Defaults to 512Mi.') +param memoryRequest string = '512Mi' + +@description('Memory limit for the mysql deployment. Defaults to 1024Mi.') +param memoryLimit string = '1024Mi' + + + +var uniqueName = 'mysql-${uniqueString(context.resource.id)}' +var mySqlImage = 'mysql:${tag}' +var port = 3306 + +resource mySql 'apps/Deployment@v1' = { + metadata: { + name: uniqueName + } + spec: { + selector: { + matchLabels: { + app: context.application.name + resource: context.resource.name + } + } + template: { + metadata: { + labels: { + app: context.application.name + resource: context.resource.name + // 'radapp.io/application': context.application == null ? '' : context.application.name + } + } + spec: { + containers: [ + { + name: 'mysql' + image: mySqlImage + ports: [ + { + containerPort: port + } + ] + resources: { + requests: { + memory: memoryRequest + } + limits: { + memory: memoryLimit + } + } + env: [ + { + name: 'MYSQL_ROOT_PASSWORD' + value: root_password + } + { + name: 'MYSQL_USER' + value: user + } + { + name: 'MYSQL_PASSWORD' + value: password + } + { + name: 'MYSQL_DATABASE' + value: database + } + ] + } + ] + } + } + } +} + +resource svc 'core/Service@v1' = { + metadata: { + name: uniqueName + labels: { + app: context.application.name + } + } + spec: { + type: 'ClusterIP' + selector: { + app: context.application.name + resource: context.resource.name + } + ports: [ + { + port: port + } + ] + } +} + +output result object = { + resources: [ + '/planes/kubernetes/local/namespaces/${svc.metadata.namespace}/providers/core/Service/${svc.metadata.name}' + '/planes/kubernetes/local/namespaces/${mySql.metadata.namespace}/providers/apps/Deployment/${mySql.metadata.name}' + ] + values: { + host: '${svc.metadata.name}.${svc.metadata.namespace}.svc.cluster.local' + port: port + database: database + user: user + } + secrets: { + #disable-next-line outputs-should-not-contain-secrets + password: password + #disable-next-line outputs-should-not-contain-secrets + root_password: root_password + } +} From ab860ba6875476eafb58c32000c454a044921368 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Fri, 12 Sep 2025 18:14:17 +0200 Subject: [PATCH 02/39] Removed platform-specific properties for better abstraction Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 6 ------ .../kubernetes/bicep/kubernetes-mySql.bicep | 15 --------------- 2 files changed, 21 deletions(-) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index a0a4ab3d..e705c84f 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -69,11 +69,5 @@ types: tag: type: string description: "(Optional) MySQL server version." - memoryRequest: - type: string - description: "(Optional) Memory request for the MySQL deployment." - memoryLimit: - type: string - description: "(Optional) Memory limit for the MySQL deployment." required: - environment \ No newline at end of file diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep index 687e032f..bc519122 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep @@ -23,13 +23,6 @@ param root_password string = uniqueString(context.resource.id, newGuid()) @description('Tag to pull for the mysql container image. Defaults to latest.') param tag string = 'latest' -@description('Memory request for the mysql deployment. Defaults to 512Mi.') -param memoryRequest string = '512Mi' - -@description('Memory limit for the mysql deployment. Defaults to 1024Mi.') -param memoryLimit string = '1024Mi' - - var uniqueName = 'mysql-${uniqueString(context.resource.id)}' var mySqlImage = 'mysql:${tag}' @@ -64,14 +57,6 @@ resource mySql 'apps/Deployment@v1' = { containerPort: port } ] - resources: { - requests: { - memory: memoryRequest - } - limits: { - memory: memoryLimit - } - } env: [ { name: 'MYSQL_ROOT_PASSWORD' From 05e5dcb4d06e47a0da86134615d2244b99669a25 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Fri, 12 Sep 2025 18:17:19 +0200 Subject: [PATCH 03/39] Removed resource-specific properties from the documentation Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 5d93d6ff..ce9e873d 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -21,8 +21,6 @@ Properties for the **Radius.Data/mySqlDatabases** resource type are provided via - `context.properties.database`(string, optional): The name of the database to create/use. - `context.properties.user`(string, optional): The username to use to connect to the database. - `context.properties.tag`(string, optional): The MySQL server version as a container tag. -- `context.properties.memoryRequest`(string, optional): Memory request for the mysql deployment. -- `context.properties.memoryLimit`(string, optional): Memory limit for the mysql deployment. ## Recipe Output Properties From 6f8127f69ad66a2e354dc0d68273c74a28c70811 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Fri, 12 Sep 2025 18:18:05 +0200 Subject: [PATCH 04/39] Added sample Radius application using the mySqlDatabases type Signed-off-by: Andrew Matveychuk --- .../recipes/samples/wordpress/app.bicep | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Data/mySqlDatabases/recipes/samples/wordpress/app.bicep diff --git a/Data/mySqlDatabases/recipes/samples/wordpress/app.bicep b/Data/mySqlDatabases/recipes/samples/wordpress/app.bicep new file mode 100644 index 00000000..bf2a7c1d --- /dev/null +++ b/Data/mySqlDatabases/recipes/samples/wordpress/app.bicep @@ -0,0 +1,56 @@ +extension radius +extension radiusResources + +@description('The Radius Application ID. Injected automatically by the rad CLI.') +param application string + +@description('The env ID of your Radius Environment. Set automatically by the rad CLI.') +param environment string + +@description('Tag to pull for the WordPress container image.') +param tag string = 'latest' + +var port int = 80 + +resource frontend 'Applications.Core/containers@2023-10-01-preview' = { + name: 'wordpress' + properties: { + application: application + environment: environment + container: { + image: 'wordpress:${tag}' + ports: { + web: { + containerPort: port + } + } + env: { + WORDPRESS_DB_HOST: { + value: '${database.properties.host}:${database.properties.port}' + } + WORDPRESS_DB_USER: { + value: database.properties.user + } + WORDPRESS_DB_PASSWORD: { + value: database.properties.password + } + WORDPRESS_DB_NAME: { + value: database.properties.database + } + } + } + connections: { + database: { + source: database.id + } + } + } +} + +resource database 'Radius.Data/mySqlDatabases@2023-10-01-preview' = { + name: 'mysql' + properties: { + application: application + environment: environment + } +} From 4ae7a70ab1dc794a9083c9ce9e62445275db462b Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Fri, 12 Sep 2025 18:20:32 +0200 Subject: [PATCH 05/39] Moved the sample to proper location Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/{recipes => }/samples/wordpress/app.bicep | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Data/mySqlDatabases/{recipes => }/samples/wordpress/app.bicep (100%) diff --git a/Data/mySqlDatabases/recipes/samples/wordpress/app.bicep b/Data/mySqlDatabases/samples/wordpress/app.bicep similarity index 100% rename from Data/mySqlDatabases/recipes/samples/wordpress/app.bicep rename to Data/mySqlDatabases/samples/wordpress/app.bicep From e82725d35929c2a136a56f55be0a892d40910dcc Mon Sep 17 00:00:00 2001 From: Zach Casper Date: Fri, 12 Sep 2025 09:41:10 -0500 Subject: [PATCH 06/39] Routes Resource Type definition (#42) Implementation of https://github.com/radius-project/design-notes/pull/110 --------- Signed-off-by: Zach Casper Signed-off-by: Andrew Matveychuk --- Compute/routes/README.md | 38 ++++++++ Compute/routes/routes.yaml | 193 +++++++++++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 Compute/routes/README.md create mode 100644 Compute/routes/routes.yaml diff --git a/Compute/routes/README.md b/Compute/routes/README.md new file mode 100644 index 00000000..40176bb1 --- /dev/null +++ b/Compute/routes/README.md @@ -0,0 +1,38 @@ +## Overview + +The Radius.Compute/routes Resource Type defines network routes for responding to external clients. It is always part of a Radius Application. It is analogous to a Kubernetes HTTPRoute, TCPRoute, TLSRoute, or UDPRoute resource. + +Developer documentation is embedded in the Resource Type definition YAML file. Developer documentation is accessible via `rad resource-type show Radius.Compute/routes`. + +## Recipes + +A list of available Recipes for this Resource Type, including links to the Bicep and Terraform templates: + +|Platform| IaC Language| Recipe Name | Stage | +|---|---|---|---| +| TODO | TODO | TODO | Alpha | + +## Recipe Input Properties + +| Radius Property | Kubernetes Property | +|---|---| +| context.properties.kind | Used by Recipe to determine which Kubernetes resource type to create (HTTPRoute, TCPRoute, TLSRoute, or UDPRoute). | +| context.properties.hostnames[] | HTTPRoute.spec.hostnames[] | +| context.properties.rules[] | HTTPRoute.spec.rules[] | +| context.properties.rules[].matches[] | HTTPRoute.spec.rules[].matches[] | +| context.properties.rules[].matches[].httpHeaders[].* | HTTPRoute.spec.rules[].matches[].headers[].* | +| context.properties.rules[].matches[].httpMethod | HTTPRoute.spec.rules[].matches[].method | +| context.properties.rules[].matches[].httpPath | HTTPRoute.spec.rules[].matches[].path.value | +| context.properties.rules[].matches[].httpQueryParams[].* | HTTPRoute.spec.rules[].matches[].queryParams[].* | +| context.properties.rules[].destinationContainer | N/A | +| context.properties.rules[].destinationContainer.resourceId | N/A | +| context.properties.rules[].destinationContainer.containerName | N/A | +| context.properties.rules[].destinationContainer.containerPortName | N/A | + +## Recipe Output Properties + +### result.listener + +- result.listener.hostname: The hostname of the listener. The listener hostname plus the paths defined by the developer constitute the URL. +- result.listener.port: The port of the listener +- result.listener.protocol: The protocol of the listener \ No newline at end of file diff --git a/Compute/routes/routes.yaml b/Compute/routes/routes.yaml new file mode 100644 index 00000000..56dd89da --- /dev/null +++ b/Compute/routes/routes.yaml @@ -0,0 +1,193 @@ +namespace: Radius.Compute +types: + routes: + description: | + The Radius.Compute/routes Resource Type defines network routes for responding to external clients. Note that a Routes resource is not required for service-to-service communication. To use Routes, define a Container and ensure a `containerPort` is specified. + + extension radius + param environment string + + resource myApplication 'Radius.Core/applications@2025-08-01-preview' = { ... } + + resource myContainer 'Radius.Compute/containers@2025-08-01-preview' = { + name: 'myContainer' + properties: { + environment: environment + application: myApplication.id + containers: { + frontend: { + image: 'frontend:1.25' + ports: { + web: { + containerPort: 8080 + } + } + } + accounts: { + image: 'accounts:1.25' + ports: { + web: { + containerPort: 8080 + } + } + } + } + } + } + + Then define a Routes resource. + + resource ingressRule 'Radius.Compute/routes@2025-08-01-preview' = { + name: 'ingressRule' + properties: { + application: myApplication.id + environment: environment + kind: 'HTTP' + rules: [ + { + matches: [ + { + httpPath: '/' + } + ] + destinationContainer: { + resourceId: myContainer.id + containerName: 'frontend' + containerPortName: 'web' + } + } + ] + } + } + + The hostname is determined by the Recipe. + + Multiple rules can be included in Routes. + + resource ingressRule 'Radius.Compute/routes@2025-08-01-preview' = { + name: 'ingressRule' + properties: { + application: myApplication.id + environment: environment + kind: 'HTTP' + rules: [ + { + matches: [ + { + httpPath: '/' + } + ] + destinationContainer: { + resourceId: myContainer.id + containerName: 'frontend' + containerPortName: 'web' + } + } + { + matches: [ + { + httpPath: '/accounts' + } + ] + destinationContainer: { + resourceId: myContainer.id + containerName: 'accounts' + containerPortName: 'web' + } + } + ] + } + } + + apiVersions: + '2025-08-01-preview': + schema: + type: object + properties: + environment: + type: string + description: (Required) The Radius Environment ID. Typically set by the rad CLI. Typically value should be `environment`. + application: + type: string + description: (Required) The Radius Application ID. `myApplication.id` for example. + kind: + type: string + enum: [HTTP, TCP, TLS, UDP] + description: (Optional) The type of rule. If not specified, `HTTPRoute` is assumed. `HTTPRoute` provides L7 ingress with support for matching based on the hostname and HTTP header. `TCPRoute` provides L4 ingress with no support for matching (all traffic is forwarded to the Container). `TLSRoute` provides L4 ingress with the ability to match based on Server Name Indication (SNI) which is equivalent to hostname in TLS. `UDPRoute` is similar to TCPRoutes but uses UDP. + hostnames: + type: array + description: (Optional) Use only when kind is HTTP or TLS. When HTTP, match against the HTTP Host header. When using TLS, match against the SNI attribute of TLS ClientHello message. Hostname may be preceded by a * wildcard. + items: + type: string + rules: + type: array + description: (Required) Rules define semantics for matching a network connection request based on conditions and forwarding the request to a Container. + items: + type: object + properties: + matches: + type: array + description: (Required) Matches define conditions used for matching a request. + items: + type: object + properties: + httpHeaders: + type: array + description: (Optional) HTTP headers to match. Specify only when kind is HTTP. Multiple match values are ANDed together. A request must match all the specified headers to match. + items: + type: object + properties: + name: + type: string + description: (Required) The name of the HTTP Header to be matched. Must be exact. + value: + type: string + description: (Required) Value of HTTP Header to be matched. + required: [name, value] + httpMethod: + type: string + description: (Optional) The HTTP method to match. Specify only when kind is HTTP. + enum: [GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH] + httpPath: + type: string + description: (Optional) The HTTP request path to match. Trailing space is ignored. Requests for `/abc`, `/abc/`, and ``/abc/def/` will all match `/abc`. + httpQueryParams: + type: array + description: (Optional) HTTP query parameters to match. Specify only when kind is HTTP. + items: + type: object + properties: + name: + type: string + description: (Required) Name of the HTTP query parameter to be matched. Specify only when kind is HTTP. + value: + type: string + description: (Required) Value of the HTTP query parameter to be matched. + required: [name, value] + destinationContainer: + type: object + properties: + resourceId: + type: string + description: (Required) The Radius Container resource ID. + containerName: + type: string + description: (Required) The specific container to target within the Container resource. + containerPortName: + type: string + description: (Required) The port name to target from the container. + required: [resourceId, containerName, containerPortName] + required: [matches, destinationContainer] + listener: + type: object + description: (Read Only) The Gateway Listener the route is assigned to. + readOnly: true + properties: + hostname: + type: string + port: + type: integer + protocol: + type: string + enum: [HTTP, HTTPS, TLS, TCP, UDP] + required: [environment, application, rules] \ No newline at end of file From 3a6e7ce9c4d4098151a2e083c6a326ea47cc2ad0 Mon Sep 17 00:00:00 2001 From: Shruthi Kumar Date: Fri, 12 Sep 2025 09:02:06 -0700 Subject: [PATCH 07/39] Add documentation for workflow testing (#44) This PR adds documentation for automated workflow testing. Testing is only required for stable resource types. The following changes have been made: - Move the build folder into .github - Add documentation for adding tests for stable resource types - Add documentation for make targets - Removed bicepconfig.json and generate it during automated workflow runs --------- Signed-off-by: sk593 Signed-off-by: Andrew Matveychuk --- {build => .github/build}/help.mk | 0 .../build}/tf-module-server/resources.yaml | 2 +- {build => .github/build}/validation.mk | 2 +- .github/scripts/update-bicepconfig.sh | 17 +++-- .github/scripts/validate-common.sh | 17 +++-- .../workflows/validate-resource-types.yaml | 4 ++ .gitignore | 3 +- Makefile | 19 ++++- Security/secrets/{ => test}/app.bicep | 0 bicepconfig.json | 6 -- .../contributing-resource-types-recipes.md | 6 +- .../contributing-resource-types-tests.md | 71 +++++++++++++++++++ 12 files changed, 127 insertions(+), 20 deletions(-) rename {build => .github/build}/help.mk (100%) rename {build => .github/build}/tf-module-server/resources.yaml (94%) rename {build => .github/build}/validation.mk (98%) rename Security/secrets/{ => test}/app.bicep (100%) delete mode 100644 bicepconfig.json create mode 100644 docs/contributing/contributing-resource-types-tests.md diff --git a/build/help.mk b/.github/build/help.mk similarity index 100% rename from build/help.mk rename to .github/build/help.mk diff --git a/build/tf-module-server/resources.yaml b/.github/build/tf-module-server/resources.yaml similarity index 94% rename from build/tf-module-server/resources.yaml rename to .github/build/tf-module-server/resources.yaml index c7dcb7b0..9ac8c659 100644 --- a/build/tf-module-server/resources.yaml +++ b/.github/build/tf-module-server/resources.yaml @@ -17,7 +17,7 @@ spec: containers: - image: mcr.microsoft.com/azurelinux/base/nginx:1.25 name: nginx - # nginx will serve files found in this directory. + # nginx will serve files found in this directory volumeMounts: - name: content mountPath: /usr/share/nginx/html diff --git a/build/validation.mk b/.github/build/validation.mk similarity index 98% rename from build/validation.mk rename to .github/build/validation.mk index 1a6fbb40..79b9c416 100644 --- a/build/validation.mk +++ b/.github/build/validation.mk @@ -44,7 +44,7 @@ publish-test-terraform-recipes: ## Publishes terraform recipes to the current Ku rm -rf "$$temp_recipes_dir" @echo -e "$(ARROW) Deploying web server..." - kubectl apply -f ./build/tf-module-server/resources.yaml -n $(TERRAFORM_MODULE_SERVER_NAMESPACE) + kubectl apply -f ./.github/build/tf-module-server/resources.yaml -n $(TERRAFORM_MODULE_SERVER_NAMESPACE) @echo -e "$(ARROW) Waiting for web server to be ready..." kubectl rollout status deployment.apps/tf-module-server -n $(TERRAFORM_MODULE_SERVER_NAMESPACE) --timeout=600s diff --git a/.github/scripts/update-bicepconfig.sh b/.github/scripts/update-bicepconfig.sh index 1bbd37ac..e10b8e8b 100755 --- a/.github/scripts/update-bicepconfig.sh +++ b/.github/scripts/update-bicepconfig.sh @@ -1,10 +1,19 @@ #!/bin/bash set -e -# Script: Update bicepconfig.json with published extensions -# This script finds all published .tgz files and adds them to bicepconfig.json +# This script creates a fresh bicepconfig.json with all published .tgz files -echo "Updating bicepconfig.json with published extensions..." +echo "Creating bicepconfig.json with published extensions..." + +# Create base bicepconfig.json with required experimental features +cat > bicepconfig.json << 'EOF' +{ + "extensions": { + "radius": "br:biceptypes.azurecr.io/radius:latest", + "aws": "br:biceptypes.azurecr.io/aws:latest" + } +} +EOF # Find all published .tgz files and add them to bicepconfig.json (safe handling) tgz_files=() @@ -29,7 +38,7 @@ if [[ ${#tgz_files[@]} -gt 0 ]]; then mv bicepconfig.tmp bicepconfig.json done - echo "✅ Successfully updated bicepconfig.json with extensions" + echo "✅ Successfully created bicepconfig.json with extensions" else echo "No extension .tgz files found to add to bicepconfig.json" fi diff --git a/.github/scripts/validate-common.sh b/.github/scripts/validate-common.sh index 681a1e61..89507c9d 100755 --- a/.github/scripts/validate-common.sh +++ b/.github/scripts/validate-common.sh @@ -32,14 +32,21 @@ find_yaml_files() { printf '%s\n' "${yaml_files[@]}" } -# Find recipe files with specific pattern +# Find recipe files with specific pattern (only in configured resource folders) find_recipe_files() { local pattern="$1" local recipe_files=() - while IFS= read -r -d '' f; do - recipe_files+=("$f") - done < <(find . -path "$pattern" -type f -print0) + for folder in "${resource_folders[@]}"; do + if [[ -d "./$folder" ]]; then + echo "Searching for recipes in folder: $folder" >&2 + while IFS= read -r -d '' f; do + recipe_files+=("$f") + done < <(find "./$folder" -path "$pattern" -type f -print0) + else + echo "Folder $folder does not exist, skipping recipe search..." >&2 + fi + done printf '%s\n' "${recipe_files[@]}" } @@ -342,7 +349,7 @@ test_recipes() { done # Deploy test application for this resource type - test_app_path="$root_folder/$resource_type/app.bicep" + test_app_path="$root_folder/$resource_type/test/app.bicep" deployment_name="test-${root_folder,,}-${platform_service}-${template_kind}-$(date +%s)" deploy_and_cleanup_test_app "$test_app_path" "$deployment_name" "for $platform_service ($template_kind recipe)" diff --git a/.github/workflows/validate-resource-types.yaml b/.github/workflows/validate-resource-types.yaml index a59366ff..63fb7e3c 100644 --- a/.github/workflows/validate-resource-types.yaml +++ b/.github/workflows/validate-resource-types.yaml @@ -3,8 +3,12 @@ name: Validate Resource Types on: push: branches: [ main ] + paths: + - '**/test/**' pull_request: branches: [ main ] + paths: + - '**/test/**' workflow_dispatch: inputs: version: diff --git a/.gitignore b/.gitignore index fe2ed02e..df6e51c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -./*.tgz \ No newline at end of file +**/*.tgz +**/bicepconfig.json \ No newline at end of file diff --git a/Makefile b/Makefile index bfb2329e..fce1fd09 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,25 @@ # limitations under the License. # ------------------------------------------------------------ +# Makefile for Radius Resource Types and Recipes Testing +# +# This Makefile provides standardized commands for testing resource types +# locally and in CI/CD pipelines. It supports Kubernetes recipe testing +# with automated setup, validation, and cleanup. +# +# Quick Start: +# make help # Show all available targets +# make install-radius # Set up local test environment +# make test-bicep-recipes # Test Kubernetes Bicep recipes +# +# Common Workflow: +# make install-radius VERSION=edge +# make create-workspace +# make create-resource-types +# make test-bicep-recipes + SHELL := /bin/bash ARROW := \033[34;1m=>\033[0m # order matters for these -include build/help.mk build/validation.mk \ No newline at end of file +include ./.github/build/help.mk ./.github/build/validation.mk \ No newline at end of file diff --git a/Security/secrets/app.bicep b/Security/secrets/test/app.bicep similarity index 100% rename from Security/secrets/app.bicep rename to Security/secrets/test/app.bicep diff --git a/bicepconfig.json b/bicepconfig.json deleted file mode 100644 index 49993a0f..00000000 --- a/bicepconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extensions": { - "radius": "br:biceptypes.azurecr.io/radius:latest", - "aws": "br:biceptypes.azurecr.io/aws:latest" - } -} \ No newline at end of file diff --git a/docs/contributing/contributing-resource-types-recipes.md b/docs/contributing/contributing-resource-types-recipes.md index c85685a3..84ff59d3 100644 --- a/docs/contributing/contributing-resource-types-recipes.md +++ b/docs/contributing/contributing-resource-types-recipes.md @@ -515,4 +515,8 @@ output "result" { - Recipes should handle different size/configuration options, allowing users to choose the appropriate configuration for their needs. - Provide outputs required to connect to the resource provisioned by the Recipe. - Use core Radius Resource Types like `containers`, `gateway` and `secrets` where applicable to ensure consistency and reusability. -- Use comments to explain complex logic or important decisions in your Recipe code. \ No newline at end of file +- Use comments to explain complex logic or important decisions in your Recipe code. + +## Integration with CI/CD Testing for Stable Resource Types + +For resource types categorized in the "Stable" maturity level, automated test coverage is required in the repository's CI/CD pipeline. The contribution guide with the steps to follow to update the automated tests can be found in [Contributing Tests for Stable Resource Types](docs/contributing/contributing-resource-types-tests.md) \ No newline at end of file diff --git a/docs/contributing/contributing-resource-types-tests.md b/docs/contributing/contributing-resource-types-tests.md new file mode 100644 index 00000000..a84d1a1b --- /dev/null +++ b/docs/contributing/contributing-resource-types-tests.md @@ -0,0 +1,71 @@ +# Contributing Tests for Stable Resource Types + +Resource Types at the Stable maturity level are required to integrate with Radius CI/CD testing. The test files are discussed below and are only relevant if you are adding test coverage for stable Resource Types. The workflow will run on your PR to validate that the Resource Type definition and Recipes are able to be created with Radius and deployed. + +### `.github/workflows` and `.github/scripts` + +This folder contains the automated testing workflows and scripts. The workflows validate Resource Type definitions, test Recipe deployments, and ensure compatibility with Radius. Scripts provide utility functions for manifest generation, resource verification, and test execution. + +### `.github/build` + +The `build` folder includes logic used to define the make targets. The `help.mk` file provides help documentation for available targets, while `validation.mk` contains all the core testing logic including Radius installation, Resource Type creation, Recipe publishing, and test execution workflows. The `tf-module-server` folder contains a container that is used to host a local module server for Terraform Recipes to referenced during testing. + +### Makefile + +The Makefile provides standardized commands for testing Resource Types locally and in CI/CD. It includes targets for installing dependencies, creating resources, publishing Recipes, running tests, and cleaning up Environments. These targets can be run locally to help with manual testing. + +## Add test coverage for stable Resource Types +These are the steps to follow to ensure that a stable Resource Type is fully integrated with Radius testing in the CI/CD pipelines. + +### Pre-requisites + +1. [**Resource Type Definition**](../contributing/contributing-resource-types-tests.md#resource-type-definition): Defines the structure and properties of your Resource Type +2. [**Recipes**](../contributing/contributing-resource-types-tests.md#recipes-for-the-resource-type): Terraform or Bicep templates for deploying the Resource Type on different platforms + +### Add an app.bicep + +### Add an app.bicep + +1. Create a new `test` folder in your Resource Type root folder. For example, for a Secrets Resource Type, the directory structure would be `/Security/secrets/test`. + +2. Create a application definition Bicep file called `app.bicep` in the test folder. Add an Application resource and a resource for your new Resource Type. Make sure to include the proper extensions for `radius` and your Resource Type. The naming of extension should be the same as your Resource Type. For example, the extension name for the `Radius.Security/secrets` Resource Type should be `secrets`. An `environment` parameter is also needed and will be set by the workflow during automated testing. + +Using the Secrets example, the full application definition should look similar to: + +``` +extension radius +extension secrets + +param environment string + +resource testapp 'Applications.Core/applications@2023-10-01-preview' = { + name: 'testapp' + properties: { + environment: environment + } +} + +resource secret 'Radius.Security/secrets@2025-08-01-preview' = { + name: 'secret' + properties: { + environment: environment + application: app.id + data: { + apikey: { + value: 'abc123xyz' + } + } + } +} +``` + +3. In `validate-common.sh`, update `setup_config()` to contain your new Resource Type. For example, if you were to add a `Radius.Compute/containers` Resource Type, the updated `setup_config()` should look like: +``` +setup_config() { + resource_folders=("Security" "Compute") + declare -g -A folder_to_namespace=( + ["Security"]="Radius.Security" + ["Compute"]="Radius.Compute" + ) +} +``` \ No newline at end of file From 02a732e156c5089dcad48792c943d4896cd9edc5 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 14:40:10 +0200 Subject: [PATCH 08/39] Removed the sample Radius application for the mySqlDatabases type Signed-off-by: Andrew Matveychuk --- .../samples/wordpress/app.bicep | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 Data/mySqlDatabases/samples/wordpress/app.bicep diff --git a/Data/mySqlDatabases/samples/wordpress/app.bicep b/Data/mySqlDatabases/samples/wordpress/app.bicep deleted file mode 100644 index bf2a7c1d..00000000 --- a/Data/mySqlDatabases/samples/wordpress/app.bicep +++ /dev/null @@ -1,56 +0,0 @@ -extension radius -extension radiusResources - -@description('The Radius Application ID. Injected automatically by the rad CLI.') -param application string - -@description('The env ID of your Radius Environment. Set automatically by the rad CLI.') -param environment string - -@description('Tag to pull for the WordPress container image.') -param tag string = 'latest' - -var port int = 80 - -resource frontend 'Applications.Core/containers@2023-10-01-preview' = { - name: 'wordpress' - properties: { - application: application - environment: environment - container: { - image: 'wordpress:${tag}' - ports: { - web: { - containerPort: port - } - } - env: { - WORDPRESS_DB_HOST: { - value: '${database.properties.host}:${database.properties.port}' - } - WORDPRESS_DB_USER: { - value: database.properties.user - } - WORDPRESS_DB_PASSWORD: { - value: database.properties.password - } - WORDPRESS_DB_NAME: { - value: database.properties.database - } - } - } - connections: { - database: { - source: database.id - } - } - } -} - -resource database 'Radius.Data/mySqlDatabases@2023-10-01-preview' = { - name: 'mysql' - properties: { - application: application - environment: environment - } -} From 6fb681789abe198d59c2cd280543ba7204df0b2c Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 14:43:58 +0200 Subject: [PATCH 09/39] Updated the API version to the resource contribution month Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index e705c84f..d84e2bee 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -34,7 +34,7 @@ types: } } apiVersions: - '2023-10-01-preview': + '2025-08-01-preview': schema: type: object properties: From f37275c95ea84e4aac6d05d83e3e58a9d1b1883c Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 14:48:41 +0200 Subject: [PATCH 10/39] Renamed the user parameter to username Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 4 ++-- Data/mySqlDatabases/mySqlDatabases.yaml | 4 ++-- .../recipes/kubernetes/bicep/kubernetes-mySql.bicep | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index ce9e873d..787de4a8 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -19,7 +19,7 @@ A list of available Recipes for this resource type, including links to the Bicep Properties for the **Radius.Data/mySqlDatabases** resource type are provided via the [Recipe Context](https://docs.radapp.io/reference/context-schema/) object. These properties include: - `context.properties.database`(string, optional): The name of the database to create/use. -- `context.properties.user`(string, optional): The username to use to connect to the database. +- `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the \-user if not provided. - `context.properties.tag`(string, optional): The MySQL server version as a container tag. ## Recipe Output Properties @@ -29,6 +29,6 @@ The **Radius.Data/mySqlDatabases** resource type expects the following output pr - `context.properties.host` (string): The hostname used to connect to the MySQL server. - `context.properties.port` (integer): The port number used to connect to the MySQL server. - `context.properties.database` (string): Database name to select on connection. -- `context.properties.user` (string): The username for connecting to the database. +- `context.properties.username` (string): The username for connecting to the database. - `context.properties.password` (string): The password for connecting to the database. - `context.properties.root_password` (string): The password for the MySQL server root user. diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index d84e2bee..cb0d54b5 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -47,9 +47,9 @@ types: database: type: string description: "(Optional) The name of the database." - user: + username: type: string - description: "(Optional) The username used to authenticate to the database." + description: "(Optional) The username for connecting to the database." password: type: string description: "(Read-only) The password used to authenticate to the database." diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep index bc519122..9a6271cb 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep @@ -10,7 +10,7 @@ extension kubernetes with { param database string = context.application.name @description('MySQL username. Defaults to -user') -param user string = '${context.application.name}-user' +param username string = '${context.application.name}-user' @description('MySQL user password. Defaults to a unique generated value.') @secure() @@ -64,7 +64,7 @@ resource mySql 'apps/Deployment@v1' = { } { name: 'MYSQL_USER' - value: user + value: username } { name: 'MYSQL_PASSWORD' @@ -112,7 +112,7 @@ output result object = { host: '${svc.metadata.name}.${svc.metadata.namespace}.svc.cluster.local' port: port database: database - user: user + username: username } secrets: { #disable-next-line outputs-should-not-contain-secrets From acd666e243f2782753f7f9101c06fb557b78a48c Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 14:57:06 +0200 Subject: [PATCH 11/39] Synced parameter descriptions Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 8 ++++---- Data/mySqlDatabases/mySqlDatabases.yaml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 787de4a8..7f717008 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -18,7 +18,7 @@ A list of available Recipes for this resource type, including links to the Bicep Properties for the **Radius.Data/mySqlDatabases** resource type are provided via the [Recipe Context](https://docs.radapp.io/reference/context-schema/) object. These properties include: -- `context.properties.database`(string, optional): The name of the database to create/use. +- `context.properties.database`(string, optional): The name of the database. Defaults to the application name if not provided. - `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the \-user if not provided. - `context.properties.tag`(string, optional): The MySQL server version as a container tag. @@ -26,9 +26,9 @@ Properties for the **Radius.Data/mySqlDatabases** resource type are provided via The **Radius.Data/mySqlDatabases** resource type expects the following output properties to be set in the Results object in the Recipe: -- `context.properties.host` (string): The hostname used to connect to the MySQL server. -- `context.properties.port` (integer): The port number used to connect to the MySQL server. -- `context.properties.database` (string): Database name to select on connection. +- `context.properties.host` (string): The hostname used to connect to the database. +- `context.properties.port` (integer): The port number used to connect to the the database. +- `context.properties.database` (string): The name of the database. - `context.properties.username` (string): The username for connecting to the database. - `context.properties.password` (string): The password for connecting to the database. - `context.properties.root_password` (string): The password for the MySQL server root user. diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index cb0d54b5..02289b04 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -40,10 +40,10 @@ types: properties: environment: type: string - description: "(Required) The Radius environmentID. Typically set by the rad CLI." + description: "(Required) The Radius EnvironmentID. Typically set by the rad CLI. Typically value should be `environment`" application: type: string - description: "(Optional) The application ID which the resource is associated with." + description: "(Optional) The Radius Application ID. `myApplication.id` for example." database: type: string description: "(Optional) The name of the database." @@ -52,11 +52,11 @@ types: description: "(Optional) The username for connecting to the database." password: type: string - description: "(Read-only) The password used to authenticate to the database." + description: "(Read-only) The password for connecting to the database." readOnly: true host: type: string - description: "(Read-only) The host name used to connected to the database." + description: "(Read-only) The host name used to connect to the database." readOnly: true port: type: integer From aae2da3a8421b2eb8691a4efcb6d6d7f0fdcbdc6 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 15:18:35 +0200 Subject: [PATCH 12/39] Removed the root_password property and moved from the container tag to major MySQL version property Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 5 ++--- Data/mySqlDatabases/mySqlDatabases.yaml | 13 +++++-------- .../kubernetes/bicep/kubernetes-mySql.bicep | 19 +++++++++---------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 7f717008..81a78116 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -20,15 +20,14 @@ Properties for the **Radius.Data/mySqlDatabases** resource type are provided via - `context.properties.database`(string, optional): The name of the database. Defaults to the application name if not provided. - `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the \-user if not provided. -- `context.properties.tag`(string, optional): The MySQL server version as a container tag. +- `context.properties.version`(string, optional): The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided. ## Recipe Output Properties The **Radius.Data/mySqlDatabases** resource type expects the following output properties to be set in the Results object in the Recipe: - `context.properties.host` (string): The hostname used to connect to the database. -- `context.properties.port` (integer): The port number used to connect to the the database. +- `context.properties.port` (integer): The port number used to connect to the MySQL server. - `context.properties.database` (string): The name of the database. - `context.properties.username` (string): The username for connecting to the database. - `context.properties.password` (string): The password for connecting to the database. -- `context.properties.root_password` (string): The password for the MySQL server root user. diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index 02289b04..dd0a580c 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -50,6 +50,10 @@ types: username: type: string description: "(Optional) The username for connecting to the database." + version: + type: string + enum: ['5.7', '8.0', '8.4'] + description: "(Optional) The major MySQL server version in the X.Y format." password: type: string description: "(Read-only) The password for connecting to the database." @@ -60,14 +64,7 @@ types: readOnly: true port: type: integer - description: "(Read-only) The port number used to connected to the the database." - readOnly: true - root_password: - type: string - description: "(Read-only) The MySQL root password." + description: "(Read-only) The port number used to connect to the the database." readOnly: true - tag: - type: string - description: "(Optional) MySQL server version." required: - environment \ No newline at end of file diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep index 9a6271cb..7e40ac1d 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep @@ -16,17 +16,18 @@ param username string = '${context.application.name}-user' @secure() param password string = uniqueString(context.resource.id, newGuid()) -@description('MySQL root user password. Defaults to a unique generated value.') -@secure() -param root_password string = uniqueString(context.resource.id, newGuid()) - -@description('Tag to pull for the mysql container image. Defaults to latest.') -param tag string = 'latest' - +@description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.') +@allowed([ + '5.7' + '8.0' + '8.4' +]) +param version string = '8.4' var uniqueName = 'mysql-${uniqueString(context.resource.id)}' -var mySqlImage = 'mysql:${tag}' +var mySqlImage = 'mysql:${version}' var port = 3306 +var root_password string = uniqueString(context.resource.id, guid(uniqueName)) resource mySql 'apps/Deployment@v1' = { metadata: { @@ -117,7 +118,5 @@ output result object = { secrets: { #disable-next-line outputs-should-not-contain-secrets password: password - #disable-next-line outputs-should-not-contain-secrets - root_password: root_password } } From ab8251dd13bf2bd88453f3657b41e99629045a6d Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 15:20:03 +0200 Subject: [PATCH 13/39] Updated type description with sample application Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 43 +++++++++++++++++++------ 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index dd0a580c..688826b6 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -7,28 +7,51 @@ types: To deploy a new MySQL database, add the mySqlDatabases resource to the application definition Bicep file. param environment string - resource mySqlDatabase 'Radius.Data/mySQL@2023-10-01-preview' = { - name: 'mySqlDatabase' + resource database 'Radius.Data/mySqlDatabases@2025-08-01-preview' = { + name: 'mysql' properties: { + application: application environment: environment } } To connect your application to the MySQL database, establish a connection from the container to the database resource as shown below. - resource myContainer 'Radius.Compute/containers@2025-08-01-preview' = { - name: 'myContainer' + @description('Tag to pull for the WordPress container image.') + param tag string = 'latest' + + var port int = 80 + + resource frontend 'Applications.Core/containers@2023-10-01-preview' = { + name: 'wordpress' properties: { + application: application environment: environment - application: myApplication.id - containers: { - frontend: { - image: 'frontend:latest' + container: { + image: 'wordpress:${tag}' + ports: { + web: { + containerPort: port + } + } + env: { + WORDPRESS_DB_HOST: { + value: '${database.properties.host}:${database.properties.port}' + } + WORDPRESS_DB_USER: { + value: database.properties.username + } + WORDPRESS_DB_PASSWORD: { + value: database.properties.password + } + WORDPRESS_DB_NAME: { + value: database.properties.database + } } } connections: { - mySql:{ - source: mySqlDatabase.id + database: { + source: database.id } } } From d9a038cb6b0b0ec4c7d9a8df849db42100ed090c Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 15:21:34 +0200 Subject: [PATCH 14/39] Updated the recipe file name to lowercase Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 81a78116..0fd0f4e5 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -12,7 +12,7 @@ A list of available Recipes for this resource type, including links to the Bicep |Platform| IaC Language| Recipe Name | Stage | |---|---|---|---| -| Kubernetes | Bicep | kubernetes-mySql.bicep | Alpha | +| Kubernetes | Bicep | kubernetes-mysql.bicep | Alpha | ## Recipe Input Properties From 725f33957834305bd4a2aec32914315339fa3a40 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 15:31:10 +0200 Subject: [PATCH 15/39] Updated the file name to lowercase Signed-off-by: Andrew Matveychuk --- .../bicep/{kubernetes-mySql.bicep => kubernetes-mysql.bicep} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Data/mySqlDatabases/recipes/kubernetes/bicep/{kubernetes-mySql.bicep => kubernetes-mysql.bicep} (100%) diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep similarity index 100% rename from Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mySql.bicep rename to Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep From d4278c49cf308b0210e97924f240dbe220b6da21 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 15 Sep 2025 15:45:32 +0200 Subject: [PATCH 16/39] Updated the port property description Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 0fd0f4e5..ed54b77f 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -27,7 +27,7 @@ Properties for the **Radius.Data/mySqlDatabases** resource type are provided via The **Radius.Data/mySqlDatabases** resource type expects the following output properties to be set in the Results object in the Recipe: - `context.properties.host` (string): The hostname used to connect to the database. -- `context.properties.port` (integer): The port number used to connect to the MySQL server. +- `context.properties.port` (integer): The port number used to connect to the database. - `context.properties.database` (string): The name of the database. - `context.properties.username` (string): The username for connecting to the database. - `context.properties.password` (string): The password for connecting to the database. From f000827a32b95a2eabe16a343cf557adbe35e24d Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Tue, 16 Sep 2025 12:23:16 +0200 Subject: [PATCH 17/39] Converted the password property to a variable instead of optional parameter tp honor the type specification Signed-off-by: Andrew Matveychuk --- .../kubernetes/bicep/kubernetes-mysql.bicep | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep index 7e40ac1d..28aa3484 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep @@ -12,10 +12,6 @@ param database string = context.application.name @description('MySQL username. Defaults to -user') param username string = '${context.application.name}-user' -@description('MySQL user password. Defaults to a unique generated value.') -@secure() -param password string = uniqueString(context.resource.id, newGuid()) - @description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.') @allowed([ '5.7' @@ -24,10 +20,20 @@ param password string = uniqueString(context.resource.id, newGuid()) ]) param version string = '8.4' +@description('Unique name for the MySQL deployment and service.') var uniqueName = 'mysql-${uniqueString(context.resource.id)}' + +@description('The MySQL container image to use.') var mySqlImage = 'mysql:${version}' + +@description('The port the MySQL server listens on.') var port = 3306 -var root_password string = uniqueString(context.resource.id, guid(uniqueName)) + +@description('MySQL user password. Defaults to a unique generated value.') +var password string = uniqueString(context.resource.id, guid(uniqueName, username)) + +@description('MySQL server root password.') +var root_password string = uniqueString(context.resource.id, guid(uniqueName, 'root')) resource mySql 'apps/Deployment@v1' = { metadata: { From fe4342c50cbe4f17134747ba112c379b87427ec3 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Wed, 17 Sep 2025 12:58:19 +0200 Subject: [PATCH 18/39] Update Data/mySqlDatabases/README.md Co-authored-by: Reshma Abdul Rahim <61033581+Reshrahim@users.noreply.github.com> Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index ed54b77f..6d269b2c 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -20,7 +20,7 @@ Properties for the **Radius.Data/mySqlDatabases** resource type are provided via - `context.properties.database`(string, optional): The name of the database. Defaults to the application name if not provided. - `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the \-user if not provided. -- `context.properties.version`(string, optional): The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided. +- `context.properties.version`(string, optional): The major MySQL server version in the X.Y format. Defaults to the version `8.4` if not provided. ## Recipe Output Properties From a3dd3532cf81dd684f4a20410959a5f7242f0290 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Wed, 17 Sep 2025 12:58:34 +0200 Subject: [PATCH 19/39] Update Data/mySqlDatabases/README.md Co-authored-by: Reshma Abdul Rahim <61033581+Reshrahim@users.noreply.github.com> Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 6d269b2c..8064d4ff 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -18,7 +18,7 @@ A list of available Recipes for this resource type, including links to the Bicep Properties for the **Radius.Data/mySqlDatabases** resource type are provided via the [Recipe Context](https://docs.radapp.io/reference/context-schema/) object. These properties include: -- `context.properties.database`(string, optional): The name of the database. Defaults to the application name if not provided. +- `context.properties.database`(string, optional): The name of the database. Defaults to the `application-name` if not provided. - `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the \-user if not provided. - `context.properties.version`(string, optional): The major MySQL server version in the X.Y format. Defaults to the version `8.4` if not provided. From 1cf69ee5ece5dacca964b6184aa9e428b83f2d35 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Wed, 17 Sep 2025 12:58:49 +0200 Subject: [PATCH 20/39] Update Data/mySqlDatabases/README.md Co-authored-by: Reshma Abdul Rahim <61033581+Reshrahim@users.noreply.github.com> Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 8064d4ff..409ecaa5 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -19,7 +19,7 @@ A list of available Recipes for this resource type, including links to the Bicep Properties for the **Radius.Data/mySqlDatabases** resource type are provided via the [Recipe Context](https://docs.radapp.io/reference/context-schema/) object. These properties include: - `context.properties.database`(string, optional): The name of the database. Defaults to the `application-name` if not provided. -- `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the \-user if not provided. +- `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the `application-name-user` if not provided. - `context.properties.version`(string, optional): The major MySQL server version in the X.Y format. Defaults to the version `8.4` if not provided. ## Recipe Output Properties From ced60b82a7e5625b8c76a46bf17b9caf98f2f513 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Wed, 17 Sep 2025 13:17:31 +0200 Subject: [PATCH 21/39] Updated the recipe with explicit evaluation for optional Bicep parameters to account for the inputs from the recipe context object Signed-off-by: Andrew Matveychuk --- .../recipes/kubernetes/bicep/kubernetes-mysql.bicep | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep index 28aa3484..e897543a 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep @@ -7,10 +7,10 @@ extension kubernetes with { } as kubernetes @description('Name of the MySQL database. Defaults to the application name.') -param database string = context.application.name +param database string = context.resource.properties.database != null ? context.resource.properties.database : context.application.name @description('MySQL username. Defaults to -user') -param username string = '${context.application.name}-user' +param username string = context.resource.properties.username != null ? context.resource.properties.username : '${context.application.name}-user' @description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.') @allowed([ @@ -18,7 +18,7 @@ param username string = '${context.application.name}-user' '8.0' '8.4' ]) -param version string = '8.4' +param version string = context.resource.properties.version != null ? context.resource.properties.version : '8.4' @description('Unique name for the MySQL deployment and service.') var uniqueName = 'mysql-${uniqueString(context.resource.id)}' From ce9a7c893d2a30cb0b6a4969a4f7cbc3573fc57e Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Thu, 18 Sep 2025 16:42:48 +0200 Subject: [PATCH 22/39] Removed WordPress-specific information from the type description for template generalization Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index 688826b6..ae08a643 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -17,37 +17,23 @@ types: To connect your application to the MySQL database, establish a connection from the container to the database resource as shown below. - @description('Tag to pull for the WordPress container image.') + @description('Tag to pull for the application container image.') param tag string = 'latest' var port int = 80 resource frontend 'Applications.Core/containers@2023-10-01-preview' = { - name: 'wordpress' + name: 'frontend' properties: { application: application environment: environment container: { - image: 'wordpress:${tag}' + image: 'your-application-container-using-mysql-database:${tag}' ports: { web: { containerPort: port } } - env: { - WORDPRESS_DB_HOST: { - value: '${database.properties.host}:${database.properties.port}' - } - WORDPRESS_DB_USER: { - value: database.properties.username - } - WORDPRESS_DB_PASSWORD: { - value: database.properties.password - } - WORDPRESS_DB_NAME: { - value: database.properties.database - } - } } connections: { database: { From 2fb0ce91e91f1dc538a28079bfca5efafbaac397 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Fri, 19 Sep 2025 17:06:40 +0200 Subject: [PATCH 23/39] Revert "Routes Resource Type definition (#42)" This reverts commit e82725d35929c2a136a56f55be0a892d40910dcc. Signed-off-by: Andrew Matveychuk --- Compute/routes/README.md | 38 -------- Compute/routes/routes.yaml | 193 ------------------------------------- 2 files changed, 231 deletions(-) delete mode 100644 Compute/routes/README.md delete mode 100644 Compute/routes/routes.yaml diff --git a/Compute/routes/README.md b/Compute/routes/README.md deleted file mode 100644 index 40176bb1..00000000 --- a/Compute/routes/README.md +++ /dev/null @@ -1,38 +0,0 @@ -## Overview - -The Radius.Compute/routes Resource Type defines network routes for responding to external clients. It is always part of a Radius Application. It is analogous to a Kubernetes HTTPRoute, TCPRoute, TLSRoute, or UDPRoute resource. - -Developer documentation is embedded in the Resource Type definition YAML file. Developer documentation is accessible via `rad resource-type show Radius.Compute/routes`. - -## Recipes - -A list of available Recipes for this Resource Type, including links to the Bicep and Terraform templates: - -|Platform| IaC Language| Recipe Name | Stage | -|---|---|---|---| -| TODO | TODO | TODO | Alpha | - -## Recipe Input Properties - -| Radius Property | Kubernetes Property | -|---|---| -| context.properties.kind | Used by Recipe to determine which Kubernetes resource type to create (HTTPRoute, TCPRoute, TLSRoute, or UDPRoute). | -| context.properties.hostnames[] | HTTPRoute.spec.hostnames[] | -| context.properties.rules[] | HTTPRoute.spec.rules[] | -| context.properties.rules[].matches[] | HTTPRoute.spec.rules[].matches[] | -| context.properties.rules[].matches[].httpHeaders[].* | HTTPRoute.spec.rules[].matches[].headers[].* | -| context.properties.rules[].matches[].httpMethod | HTTPRoute.spec.rules[].matches[].method | -| context.properties.rules[].matches[].httpPath | HTTPRoute.spec.rules[].matches[].path.value | -| context.properties.rules[].matches[].httpQueryParams[].* | HTTPRoute.spec.rules[].matches[].queryParams[].* | -| context.properties.rules[].destinationContainer | N/A | -| context.properties.rules[].destinationContainer.resourceId | N/A | -| context.properties.rules[].destinationContainer.containerName | N/A | -| context.properties.rules[].destinationContainer.containerPortName | N/A | - -## Recipe Output Properties - -### result.listener - -- result.listener.hostname: The hostname of the listener. The listener hostname plus the paths defined by the developer constitute the URL. -- result.listener.port: The port of the listener -- result.listener.protocol: The protocol of the listener \ No newline at end of file diff --git a/Compute/routes/routes.yaml b/Compute/routes/routes.yaml deleted file mode 100644 index 56dd89da..00000000 --- a/Compute/routes/routes.yaml +++ /dev/null @@ -1,193 +0,0 @@ -namespace: Radius.Compute -types: - routes: - description: | - The Radius.Compute/routes Resource Type defines network routes for responding to external clients. Note that a Routes resource is not required for service-to-service communication. To use Routes, define a Container and ensure a `containerPort` is specified. - - extension radius - param environment string - - resource myApplication 'Radius.Core/applications@2025-08-01-preview' = { ... } - - resource myContainer 'Radius.Compute/containers@2025-08-01-preview' = { - name: 'myContainer' - properties: { - environment: environment - application: myApplication.id - containers: { - frontend: { - image: 'frontend:1.25' - ports: { - web: { - containerPort: 8080 - } - } - } - accounts: { - image: 'accounts:1.25' - ports: { - web: { - containerPort: 8080 - } - } - } - } - } - } - - Then define a Routes resource. - - resource ingressRule 'Radius.Compute/routes@2025-08-01-preview' = { - name: 'ingressRule' - properties: { - application: myApplication.id - environment: environment - kind: 'HTTP' - rules: [ - { - matches: [ - { - httpPath: '/' - } - ] - destinationContainer: { - resourceId: myContainer.id - containerName: 'frontend' - containerPortName: 'web' - } - } - ] - } - } - - The hostname is determined by the Recipe. - - Multiple rules can be included in Routes. - - resource ingressRule 'Radius.Compute/routes@2025-08-01-preview' = { - name: 'ingressRule' - properties: { - application: myApplication.id - environment: environment - kind: 'HTTP' - rules: [ - { - matches: [ - { - httpPath: '/' - } - ] - destinationContainer: { - resourceId: myContainer.id - containerName: 'frontend' - containerPortName: 'web' - } - } - { - matches: [ - { - httpPath: '/accounts' - } - ] - destinationContainer: { - resourceId: myContainer.id - containerName: 'accounts' - containerPortName: 'web' - } - } - ] - } - } - - apiVersions: - '2025-08-01-preview': - schema: - type: object - properties: - environment: - type: string - description: (Required) The Radius Environment ID. Typically set by the rad CLI. Typically value should be `environment`. - application: - type: string - description: (Required) The Radius Application ID. `myApplication.id` for example. - kind: - type: string - enum: [HTTP, TCP, TLS, UDP] - description: (Optional) The type of rule. If not specified, `HTTPRoute` is assumed. `HTTPRoute` provides L7 ingress with support for matching based on the hostname and HTTP header. `TCPRoute` provides L4 ingress with no support for matching (all traffic is forwarded to the Container). `TLSRoute` provides L4 ingress with the ability to match based on Server Name Indication (SNI) which is equivalent to hostname in TLS. `UDPRoute` is similar to TCPRoutes but uses UDP. - hostnames: - type: array - description: (Optional) Use only when kind is HTTP or TLS. When HTTP, match against the HTTP Host header. When using TLS, match against the SNI attribute of TLS ClientHello message. Hostname may be preceded by a * wildcard. - items: - type: string - rules: - type: array - description: (Required) Rules define semantics for matching a network connection request based on conditions and forwarding the request to a Container. - items: - type: object - properties: - matches: - type: array - description: (Required) Matches define conditions used for matching a request. - items: - type: object - properties: - httpHeaders: - type: array - description: (Optional) HTTP headers to match. Specify only when kind is HTTP. Multiple match values are ANDed together. A request must match all the specified headers to match. - items: - type: object - properties: - name: - type: string - description: (Required) The name of the HTTP Header to be matched. Must be exact. - value: - type: string - description: (Required) Value of HTTP Header to be matched. - required: [name, value] - httpMethod: - type: string - description: (Optional) The HTTP method to match. Specify only when kind is HTTP. - enum: [GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH] - httpPath: - type: string - description: (Optional) The HTTP request path to match. Trailing space is ignored. Requests for `/abc`, `/abc/`, and ``/abc/def/` will all match `/abc`. - httpQueryParams: - type: array - description: (Optional) HTTP query parameters to match. Specify only when kind is HTTP. - items: - type: object - properties: - name: - type: string - description: (Required) Name of the HTTP query parameter to be matched. Specify only when kind is HTTP. - value: - type: string - description: (Required) Value of the HTTP query parameter to be matched. - required: [name, value] - destinationContainer: - type: object - properties: - resourceId: - type: string - description: (Required) The Radius Container resource ID. - containerName: - type: string - description: (Required) The specific container to target within the Container resource. - containerPortName: - type: string - description: (Required) The port name to target from the container. - required: [resourceId, containerName, containerPortName] - required: [matches, destinationContainer] - listener: - type: object - description: (Read Only) The Gateway Listener the route is assigned to. - readOnly: true - properties: - hostname: - type: string - port: - type: integer - protocol: - type: string - enum: [HTTP, HTTPS, TLS, TCP, UDP] - required: [environment, application, rules] \ No newline at end of file From a75746466489a9a136d3db4fb43073afd3f9513f Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Fri, 19 Sep 2025 17:07:24 +0200 Subject: [PATCH 24/39] Revert "Add documentation for workflow testing (#44)" This reverts commit 3a6e7ce9c4d4098151a2e083c6a326ea47cc2ad0. Signed-off-by: Andrew Matveychuk --- .github/scripts/update-bicepconfig.sh | 17 ++--- .github/scripts/validate-common.sh | 17 ++--- .../workflows/validate-resource-types.yaml | 4 -- .gitignore | 3 +- Makefile | 19 +---- Security/secrets/{test => }/app.bicep | 0 bicepconfig.json | 6 ++ {.github/build => build}/help.mk | 0 .../tf-module-server/resources.yaml | 2 +- {.github/build => build}/validation.mk | 2 +- .../contributing-resource-types-recipes.md | 6 +- .../contributing-resource-types-tests.md | 71 ------------------- 12 files changed, 20 insertions(+), 127 deletions(-) rename Security/secrets/{test => }/app.bicep (100%) create mode 100644 bicepconfig.json rename {.github/build => build}/help.mk (100%) rename {.github/build => build}/tf-module-server/resources.yaml (94%) rename {.github/build => build}/validation.mk (98%) delete mode 100644 docs/contributing/contributing-resource-types-tests.md diff --git a/.github/scripts/update-bicepconfig.sh b/.github/scripts/update-bicepconfig.sh index e10b8e8b..1bbd37ac 100755 --- a/.github/scripts/update-bicepconfig.sh +++ b/.github/scripts/update-bicepconfig.sh @@ -1,19 +1,10 @@ #!/bin/bash set -e -# This script creates a fresh bicepconfig.json with all published .tgz files +# Script: Update bicepconfig.json with published extensions +# This script finds all published .tgz files and adds them to bicepconfig.json -echo "Creating bicepconfig.json with published extensions..." - -# Create base bicepconfig.json with required experimental features -cat > bicepconfig.json << 'EOF' -{ - "extensions": { - "radius": "br:biceptypes.azurecr.io/radius:latest", - "aws": "br:biceptypes.azurecr.io/aws:latest" - } -} -EOF +echo "Updating bicepconfig.json with published extensions..." # Find all published .tgz files and add them to bicepconfig.json (safe handling) tgz_files=() @@ -38,7 +29,7 @@ if [[ ${#tgz_files[@]} -gt 0 ]]; then mv bicepconfig.tmp bicepconfig.json done - echo "✅ Successfully created bicepconfig.json with extensions" + echo "✅ Successfully updated bicepconfig.json with extensions" else echo "No extension .tgz files found to add to bicepconfig.json" fi diff --git a/.github/scripts/validate-common.sh b/.github/scripts/validate-common.sh index 89507c9d..681a1e61 100755 --- a/.github/scripts/validate-common.sh +++ b/.github/scripts/validate-common.sh @@ -32,21 +32,14 @@ find_yaml_files() { printf '%s\n' "${yaml_files[@]}" } -# Find recipe files with specific pattern (only in configured resource folders) +# Find recipe files with specific pattern find_recipe_files() { local pattern="$1" local recipe_files=() - for folder in "${resource_folders[@]}"; do - if [[ -d "./$folder" ]]; then - echo "Searching for recipes in folder: $folder" >&2 - while IFS= read -r -d '' f; do - recipe_files+=("$f") - done < <(find "./$folder" -path "$pattern" -type f -print0) - else - echo "Folder $folder does not exist, skipping recipe search..." >&2 - fi - done + while IFS= read -r -d '' f; do + recipe_files+=("$f") + done < <(find . -path "$pattern" -type f -print0) printf '%s\n' "${recipe_files[@]}" } @@ -349,7 +342,7 @@ test_recipes() { done # Deploy test application for this resource type - test_app_path="$root_folder/$resource_type/test/app.bicep" + test_app_path="$root_folder/$resource_type/app.bicep" deployment_name="test-${root_folder,,}-${platform_service}-${template_kind}-$(date +%s)" deploy_and_cleanup_test_app "$test_app_path" "$deployment_name" "for $platform_service ($template_kind recipe)" diff --git a/.github/workflows/validate-resource-types.yaml b/.github/workflows/validate-resource-types.yaml index 63fb7e3c..a59366ff 100644 --- a/.github/workflows/validate-resource-types.yaml +++ b/.github/workflows/validate-resource-types.yaml @@ -3,12 +3,8 @@ name: Validate Resource Types on: push: branches: [ main ] - paths: - - '**/test/**' pull_request: branches: [ main ] - paths: - - '**/test/**' workflow_dispatch: inputs: version: diff --git a/.gitignore b/.gitignore index df6e51c4..fe2ed02e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -**/*.tgz -**/bicepconfig.json \ No newline at end of file +./*.tgz \ No newline at end of file diff --git a/Makefile b/Makefile index fce1fd09..bfb2329e 100644 --- a/Makefile +++ b/Makefile @@ -14,25 +14,8 @@ # limitations under the License. # ------------------------------------------------------------ -# Makefile for Radius Resource Types and Recipes Testing -# -# This Makefile provides standardized commands for testing resource types -# locally and in CI/CD pipelines. It supports Kubernetes recipe testing -# with automated setup, validation, and cleanup. -# -# Quick Start: -# make help # Show all available targets -# make install-radius # Set up local test environment -# make test-bicep-recipes # Test Kubernetes Bicep recipes -# -# Common Workflow: -# make install-radius VERSION=edge -# make create-workspace -# make create-resource-types -# make test-bicep-recipes - SHELL := /bin/bash ARROW := \033[34;1m=>\033[0m # order matters for these -include ./.github/build/help.mk ./.github/build/validation.mk \ No newline at end of file +include build/help.mk build/validation.mk \ No newline at end of file diff --git a/Security/secrets/test/app.bicep b/Security/secrets/app.bicep similarity index 100% rename from Security/secrets/test/app.bicep rename to Security/secrets/app.bicep diff --git a/bicepconfig.json b/bicepconfig.json new file mode 100644 index 00000000..49993a0f --- /dev/null +++ b/bicepconfig.json @@ -0,0 +1,6 @@ +{ + "extensions": { + "radius": "br:biceptypes.azurecr.io/radius:latest", + "aws": "br:biceptypes.azurecr.io/aws:latest" + } +} \ No newline at end of file diff --git a/.github/build/help.mk b/build/help.mk similarity index 100% rename from .github/build/help.mk rename to build/help.mk diff --git a/.github/build/tf-module-server/resources.yaml b/build/tf-module-server/resources.yaml similarity index 94% rename from .github/build/tf-module-server/resources.yaml rename to build/tf-module-server/resources.yaml index 9ac8c659..c7dcb7b0 100644 --- a/.github/build/tf-module-server/resources.yaml +++ b/build/tf-module-server/resources.yaml @@ -17,7 +17,7 @@ spec: containers: - image: mcr.microsoft.com/azurelinux/base/nginx:1.25 name: nginx - # nginx will serve files found in this directory + # nginx will serve files found in this directory. volumeMounts: - name: content mountPath: /usr/share/nginx/html diff --git a/.github/build/validation.mk b/build/validation.mk similarity index 98% rename from .github/build/validation.mk rename to build/validation.mk index 79b9c416..1a6fbb40 100644 --- a/.github/build/validation.mk +++ b/build/validation.mk @@ -44,7 +44,7 @@ publish-test-terraform-recipes: ## Publishes terraform recipes to the current Ku rm -rf "$$temp_recipes_dir" @echo -e "$(ARROW) Deploying web server..." - kubectl apply -f ./.github/build/tf-module-server/resources.yaml -n $(TERRAFORM_MODULE_SERVER_NAMESPACE) + kubectl apply -f ./build/tf-module-server/resources.yaml -n $(TERRAFORM_MODULE_SERVER_NAMESPACE) @echo -e "$(ARROW) Waiting for web server to be ready..." kubectl rollout status deployment.apps/tf-module-server -n $(TERRAFORM_MODULE_SERVER_NAMESPACE) --timeout=600s diff --git a/docs/contributing/contributing-resource-types-recipes.md b/docs/contributing/contributing-resource-types-recipes.md index 84ff59d3..c85685a3 100644 --- a/docs/contributing/contributing-resource-types-recipes.md +++ b/docs/contributing/contributing-resource-types-recipes.md @@ -515,8 +515,4 @@ output "result" { - Recipes should handle different size/configuration options, allowing users to choose the appropriate configuration for their needs. - Provide outputs required to connect to the resource provisioned by the Recipe. - Use core Radius Resource Types like `containers`, `gateway` and `secrets` where applicable to ensure consistency and reusability. -- Use comments to explain complex logic or important decisions in your Recipe code. - -## Integration with CI/CD Testing for Stable Resource Types - -For resource types categorized in the "Stable" maturity level, automated test coverage is required in the repository's CI/CD pipeline. The contribution guide with the steps to follow to update the automated tests can be found in [Contributing Tests for Stable Resource Types](docs/contributing/contributing-resource-types-tests.md) \ No newline at end of file +- Use comments to explain complex logic or important decisions in your Recipe code. \ No newline at end of file diff --git a/docs/contributing/contributing-resource-types-tests.md b/docs/contributing/contributing-resource-types-tests.md deleted file mode 100644 index a84d1a1b..00000000 --- a/docs/contributing/contributing-resource-types-tests.md +++ /dev/null @@ -1,71 +0,0 @@ -# Contributing Tests for Stable Resource Types - -Resource Types at the Stable maturity level are required to integrate with Radius CI/CD testing. The test files are discussed below and are only relevant if you are adding test coverage for stable Resource Types. The workflow will run on your PR to validate that the Resource Type definition and Recipes are able to be created with Radius and deployed. - -### `.github/workflows` and `.github/scripts` - -This folder contains the automated testing workflows and scripts. The workflows validate Resource Type definitions, test Recipe deployments, and ensure compatibility with Radius. Scripts provide utility functions for manifest generation, resource verification, and test execution. - -### `.github/build` - -The `build` folder includes logic used to define the make targets. The `help.mk` file provides help documentation for available targets, while `validation.mk` contains all the core testing logic including Radius installation, Resource Type creation, Recipe publishing, and test execution workflows. The `tf-module-server` folder contains a container that is used to host a local module server for Terraform Recipes to referenced during testing. - -### Makefile - -The Makefile provides standardized commands for testing Resource Types locally and in CI/CD. It includes targets for installing dependencies, creating resources, publishing Recipes, running tests, and cleaning up Environments. These targets can be run locally to help with manual testing. - -## Add test coverage for stable Resource Types -These are the steps to follow to ensure that a stable Resource Type is fully integrated with Radius testing in the CI/CD pipelines. - -### Pre-requisites - -1. [**Resource Type Definition**](../contributing/contributing-resource-types-tests.md#resource-type-definition): Defines the structure and properties of your Resource Type -2. [**Recipes**](../contributing/contributing-resource-types-tests.md#recipes-for-the-resource-type): Terraform or Bicep templates for deploying the Resource Type on different platforms - -### Add an app.bicep - -### Add an app.bicep - -1. Create a new `test` folder in your Resource Type root folder. For example, for a Secrets Resource Type, the directory structure would be `/Security/secrets/test`. - -2. Create a application definition Bicep file called `app.bicep` in the test folder. Add an Application resource and a resource for your new Resource Type. Make sure to include the proper extensions for `radius` and your Resource Type. The naming of extension should be the same as your Resource Type. For example, the extension name for the `Radius.Security/secrets` Resource Type should be `secrets`. An `environment` parameter is also needed and will be set by the workflow during automated testing. - -Using the Secrets example, the full application definition should look similar to: - -``` -extension radius -extension secrets - -param environment string - -resource testapp 'Applications.Core/applications@2023-10-01-preview' = { - name: 'testapp' - properties: { - environment: environment - } -} - -resource secret 'Radius.Security/secrets@2025-08-01-preview' = { - name: 'secret' - properties: { - environment: environment - application: app.id - data: { - apikey: { - value: 'abc123xyz' - } - } - } -} -``` - -3. In `validate-common.sh`, update `setup_config()` to contain your new Resource Type. For example, if you were to add a `Radius.Compute/containers` Resource Type, the updated `setup_config()` should look like: -``` -setup_config() { - resource_folders=("Security" "Compute") - declare -g -A folder_to_namespace=( - ["Security"]="Radius.Security" - ["Compute"]="Radius.Compute" - ) -} -``` \ No newline at end of file From b3dae084e7ded364cf373a61ae27de859c6ee79f Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Tue, 23 Sep 2025 14:12:08 +0200 Subject: [PATCH 25/39] Updated parameter validation to use Bicep safe access operator Signed-off-by: Andrew Matveychuk --- .../recipes/kubernetes/bicep/kubernetes-mysql.bicep | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep index e897543a..ec0b6745 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep @@ -7,10 +7,10 @@ extension kubernetes with { } as kubernetes @description('Name of the MySQL database. Defaults to the application name.') -param database string = context.resource.properties.database != null ? context.resource.properties.database : context.application.name +param database string = context.resource.properties.?database ?? '${context.application.name}' @description('MySQL username. Defaults to -user') -param username string = context.resource.properties.username != null ? context.resource.properties.username : '${context.application.name}-user' +param username string = context.resource.properties.?username ?? '${context.application.name}-user' @description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.') @allowed([ @@ -18,7 +18,7 @@ param username string = context.resource.properties.username != null ? context.r '8.0' '8.4' ]) -param version string = context.resource.properties.version != null ? context.resource.properties.version : '8.4' +param version string = context.resource.properties.?version ?? '8.4' @description('Unique name for the MySQL deployment and service.') var uniqueName = 'mysql-${uniqueString(context.resource.id)}' From 86a05cbf111e4fc0bea9c898cd85c3ea315257fa Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Tue, 23 Sep 2025 14:15:01 +0200 Subject: [PATCH 26/39] Updated type description Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index ae08a643..b1b62c1d 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -6,26 +6,29 @@ types: To deploy a new MySQL database, add the mySqlDatabases resource to the application definition Bicep file. + extension Radius + + resource myApplication 'Applications.Core/applications@2023-10-01-preview' = { ... } + param environment string resource database 'Radius.Data/mySqlDatabases@2025-08-01-preview' = { - name: 'mysql' properties: { - application: application + application: myApplication.id environment: environment } } - To connect your application to the MySQL database, establish a connection from the container to the database resource as shown below. + + For example, to connect to the MySQL database from a container, establish a connection to the database resource as shown below. @description('Tag to pull for the application container image.') param tag string = 'latest' var port int = 80 - resource frontend 'Applications.Core/containers@2023-10-01-preview' = { name: 'frontend' properties: { - application: application + application: myApplication.id environment: environment container: { image: 'your-application-container-using-mysql-database:${tag}' From 098a6b9d70995a2c51d095344e14ccdfa04cc115 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Thu, 2 Oct 2025 11:37:11 +0200 Subject: [PATCH 27/39] Added MySQL recipe for Azure Database for MySQL Flexible Server Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/README.md | 2 + Data/mySqlDatabases/mySqlDatabases.yaml | 45 +++++++++- .../bicep/azure-database-for-mysql.bicep | 83 +++++++++++++++++++ 3 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep diff --git a/Data/mySqlDatabases/README.md b/Data/mySqlDatabases/README.md index 409ecaa5..30ce7c93 100644 --- a/Data/mySqlDatabases/README.md +++ b/Data/mySqlDatabases/README.md @@ -13,6 +13,7 @@ A list of available Recipes for this resource type, including links to the Bicep |Platform| IaC Language| Recipe Name | Stage | |---|---|---|---| | Kubernetes | Bicep | kubernetes-mysql.bicep | Alpha | +| Azure | Bicep | azure-database-for-mysql.bicep | Alpha | ## Recipe Input Properties @@ -21,6 +22,7 @@ Properties for the **Radius.Data/mySqlDatabases** resource type are provided via - `context.properties.database`(string, optional): The name of the database. Defaults to the `application-name` if not provided. - `context.properties.username`(string, optional): The username for connecting to the database. Defaults to the `application-name-user` if not provided. - `context.properties.version`(string, optional): The major MySQL server version in the X.Y format. Defaults to the version `8.4` if not provided. +- `context.properties.tags`(object, optional): The user-defined tags that will be applied to the resource. Default is null. ## Recipe Output Properties diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index b0c807fe..4950e281 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -5,7 +5,7 @@ types: The Radius.Data/mySqlDatabases Resource Type deploys a MySQL database. To deploy a new MySQL database, add the mySqlDatabases resource to the application definition Bicep file. extension radius - param environment string + param environment string resource myApplication 'Applications.Core/applications@2023-10-01-preview' = { ... } @@ -17,7 +17,7 @@ types: } } - To connect your container to the database, create a connection from the Container resource to the database as shown below. + To connect your container to the database, create a connection from the Container resource to the database as shown below. resource frontend 'Applications.Core/containers@2023-10-01-preview' = { name: 'frontend' @@ -41,7 +41,7 @@ types: } The connection automatically injects environment variables into the container for all properties from the database. The environment variables are named `CONNECTION__`. In this example, the connection name is `mysqldb` so the environment variables will be: - + CONNECTION_MYSQLDB_DATABASE CONNECTION_MYSQLDB_USERNAME CONNECTION_MYSQLDB_PASSWORD @@ -69,7 +69,44 @@ types: version: type: string enum: ['5.7', '8.0', '8.4'] - description: "(Optional) The major MySQL server version in the X.Y format. Assumed to be 8.4 if not specified." + description: "(Optional) The major MySQL server version in the X.Y format. Assumed to be 8.4 if not specified." + password: + type: string + description: "(Read-only) The password for connecting to the database." + readOnly: true + host: + type: string + description: "(Read-only) The host name used to connect to the database." + readOnly: true + port: + type: integer + description: "(Read-only) The port number used to connect to the the database." + readOnly: true + required: + - environment + '2025-10-01-preview': + schema: + type: object + properties: + environment: + type: string + description: "(Required) The Radius EnvironmentID. Typically set by the rad CLI. Typically value should be `environment`" + application: + type: string + description: "(Optional) The Radius Application ID. `myApplication.id` for example." + database: + type: string + description: "(Optional) The name of the database." + username: + type: string + description: "(Optional) The username for connecting to the database." + version: + type: string + enum: ['5.7', '8.0', '8.4'] + description: "(Optional) The major MySQL server version in the X.Y format. Assumed to be 8.4 if not specified." + tags: + type: object + description: "(Optional) The user-defined tags that will be applied to the resource. Default is null." password: type: string description: "(Read-only) The password for connecting to the database." diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep new file mode 100644 index 00000000..ce00608e --- /dev/null +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -0,0 +1,83 @@ +@description('Information about what resource is calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.io/reference/context-schema/ ') +param context object + +@description('Name of the MySQL database. Defaults to the application name.') +param database string = context.resource.properties.?database ?? '${context.application.name}' + +@description('MySQL username. Defaults to -user') +param username string = context.resource.properties.?username ?? '${context.application.name}-user' + +@description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.') +@allowed([ + '5.7' + '8.0' + '8.4' +]) +param version string = context.resource.properties.?version ?? '8.4' + +@description('The user-defined tags that will be applied to the resource. Default is null.') +param tags object = {} + +@description('The Radius specific tags that will be applied to the resource') +var radiusTags = { + 'radapp.io-environment': context.environment.id + 'radapp.io-application': context.application == null ? '' : context.application.id + 'radapp.io-resource': context.resource.id +} + +@description('Location to deploy the resources') +var location string = resourceGroup().location + +@description('Unique name for the MySQL deployment and service.') +var uniqueName = 'mysql-${uniqueString(context.resource.id)}' + +@description('The port the MySQL server listens on.') +var port = 3306 + +@description('MySQL server root password.') +var root_password string = uniqueString(context.resource.id, guid(uniqueName, username)) + +resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2024-12-01-preview' = { + name: uniqueName + location: location + tags: union(tags, radiusTags) + sku: { + name: 'Standard_B1ms' + tier: 'Burstable' + } + properties: { + createMode: 'Default' + version: (version == '8.0') ? '8.0.21' : version + administratorLogin: username + administratorLoginPassword: root_password + databasePort: port + storage: { + storageSizeGB: 32 + } + network: { + publicNetworkAccess: 'Enabled' + } + } +} + +resource mysqlDatabase 'Microsoft.DBforMySQL/flexibleServers/databases@2024-12-01-preview' = { + parent: mysqlServer + name: database + properties: { + charset: 'utf8' + collation: 'utf8_general_ci' + } +} + +output result object = { + values: { + host: mysqlServer.properties.fullyQualifiedDomainName + port: mysqlServer.properties.databasePort + database: mysqlDatabase.name + username: mysqlServer.properties.administratorLogin + } + secrets: { + #disable-next-line outputs-should-not-contain-secrets + password: root_password + } +} From 9a4e8b35233284b3e827ac5464e023ad2018d2b1 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Thu, 2 Oct 2025 11:38:05 +0200 Subject: [PATCH 28/39] Added the new optional tags property to the MySQL recipe for Kubernetes Signed-off-by: Andrew Matveychuk --- .../recipes/kubernetes/bicep/kubernetes-mysql.bicep | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep index 684b8e1c..a8a89241 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep @@ -20,6 +20,9 @@ param username string = context.resource.properties.?username ?? '${context.appl ]) param version string = context.resource.properties.?version ?? '8.4' +@description('The user-defined tags that will be applied to the resource. Default is null.') +param tags object = {} + @description('Unique name for the MySQL deployment and service.') var uniqueName = 'mysql-${uniqueString(context.resource.id)}' @@ -38,6 +41,7 @@ var root_password string = uniqueString(context.resource.id, guid(uniqueName, 'r resource mySql 'apps/Deployment@v1' = { metadata: { name: uniqueName + labels: tags } spec: { selector: { From 942cd9319db9ad96a52a8dc0574222a77e7330b3 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Thu, 2 Oct 2025 16:07:40 +0200 Subject: [PATCH 29/39] Fixed the tag property definition in the 'Radius.Data/mySqlDatabases' type Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index 4950e281..568ff5f0 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -107,6 +107,13 @@ types: tags: type: object description: "(Optional) The user-defined tags that will be applied to the resource. Default is null." + additionalProperties: + type: string + description: "(Optional) Tag name." + properties: + value: + type: string + description: "(Optional) Tag value." password: type: string description: "(Read-only) The password for connecting to the database." From 9428816631866d25f1c80e7e6eece5f93285e0ec Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Thu, 2 Oct 2025 16:09:08 +0200 Subject: [PATCH 30/39] Fixed tag handling in recipes Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 2 +- .../recipes/kubernetes/bicep/kubernetes-mysql.bicep | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index ce00608e..f62625bc 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -16,7 +16,7 @@ param username string = context.resource.properties.?username ?? '${context.appl param version string = context.resource.properties.?version ?? '8.4' @description('The user-defined tags that will be applied to the resource. Default is null.') -param tags object = {} +param tags object = context.resource.properties.?tags ?? {} @description('The Radius specific tags that will be applied to the resource') var radiusTags = { diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep index a8a89241..13e394bc 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep @@ -21,7 +21,7 @@ param username string = context.resource.properties.?username ?? '${context.appl param version string = context.resource.properties.?version ?? '8.4' @description('The user-defined tags that will be applied to the resource. Default is null.') -param tags object = {} +param tags object = context.resource.properties.?tags ?? {} @description('Unique name for the MySQL deployment and service.') var uniqueName = 'mysql-${uniqueString(context.resource.id)}' From 30cc774d10b9c990621eb300964a774e7925ffef Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 6 Oct 2025 11:50:01 +0200 Subject: [PATCH 31/39] Removed special character from MySQL default username and added validation for maximum length Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 5 +++-- .../recipes/kubernetes/bicep/kubernetes-mysql.bicep | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index f62625bc..12c725d3 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -4,8 +4,9 @@ param context object @description('Name of the MySQL database. Defaults to the application name.') param database string = context.resource.properties.?database ?? '${context.application.name}' -@description('MySQL username. Defaults to -user') -param username string = context.resource.properties.?username ?? '${context.application.name}-user' +@maxLength(32) +@description('MySQL username. Defaults to _user') +param username string = context.resource.properties.?username ?? '${context.application.name}_user' @description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.') @allowed([ diff --git a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep index 13e394bc..4b15c4d9 100644 --- a/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep +++ b/Data/mySqlDatabases/recipes/kubernetes/bicep/kubernetes-mysql.bicep @@ -9,8 +9,9 @@ extension kubernetes with { @description('Name of the MySQL database. Defaults to the application name.') param database string = context.resource.properties.?database ?? '${context.application.name}' -@description('MySQL username. Defaults to -user') -param username string = context.resource.properties.?username ?? '${context.application.name}-user' +@description('MySQL username. Defaults to _user') +@maxLength(32) +param username string = context.resource.properties.?username ?? '${context.application.name}_user' @description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.') @allowed([ From 7611c33b3ecd3edac0eed61a98203dff60722d1c Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 6 Oct 2025 12:24:41 +0200 Subject: [PATCH 32/39] Merged the new type version into existing one and added info about property default values Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 38 ++----------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index 568ff5f0..90f96190 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -62,44 +62,10 @@ types: description: "(Optional) The Radius Application ID. `myApplication.id` for example." database: type: string - description: "(Optional) The name of the database." + description: "(Optional) The name of the database. Assumed to be `myApplication.name` if not specified." username: type: string - description: "(Optional) The username for connecting to the database." - version: - type: string - enum: ['5.7', '8.0', '8.4'] - description: "(Optional) The major MySQL server version in the X.Y format. Assumed to be 8.4 if not specified." - password: - type: string - description: "(Read-only) The password for connecting to the database." - readOnly: true - host: - type: string - description: "(Read-only) The host name used to connect to the database." - readOnly: true - port: - type: integer - description: "(Read-only) The port number used to connect to the the database." - readOnly: true - required: - - environment - '2025-10-01-preview': - schema: - type: object - properties: - environment: - type: string - description: "(Required) The Radius EnvironmentID. Typically set by the rad CLI. Typically value should be `environment`" - application: - type: string - description: "(Optional) The Radius Application ID. `myApplication.id` for example." - database: - type: string - description: "(Optional) The name of the database." - username: - type: string - description: "(Optional) The username for connecting to the database." + description: "(Optional) The username for connecting to the database. Assumed to be `_user` if not specified." version: type: string enum: ['5.7', '8.0', '8.4'] From 5528e866b1e1bb41a0d1fe746bc6a4659d8a916e Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 6 Oct 2025 12:27:01 +0200 Subject: [PATCH 33/39] Converted the auto-generated password variable to a parameter to overcome the current limitation of working with secrets in Radius Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index 12c725d3..1aecd314 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -36,7 +36,8 @@ var uniqueName = 'mysql-${uniqueString(context.resource.id)}' var port = 3306 @description('MySQL server root password.') -var root_password string = uniqueString(context.resource.id, guid(uniqueName, username)) +@secure() +param root_password string = uniqueString(context.resource.id, newGuid()) resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2024-12-01-preview' = { name: uniqueName From 615ec04bea9b372538e63435253f38ff75e244e4 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 13 Oct 2025 12:27:49 +0200 Subject: [PATCH 34/39] Removed double-referencing in the output object Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index 1aecd314..34f88b7a 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -74,9 +74,9 @@ resource mysqlDatabase 'Microsoft.DBforMySQL/flexibleServers/databases@2024-12-0 output result object = { values: { host: mysqlServer.properties.fullyQualifiedDomainName - port: mysqlServer.properties.databasePort - database: mysqlDatabase.name - username: mysqlServer.properties.administratorLogin + port: port + database: database + username: username } secrets: { #disable-next-line outputs-should-not-contain-secrets From 80e745e9ab7f91b5b672c49e272b9f17e786c105 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 13 Oct 2025 12:29:10 +0200 Subject: [PATCH 35/39] Converted database to nested resource Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index 34f88b7a..3e33ac9f 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -58,18 +58,18 @@ resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2024-12-01-preview' = } network: { publicNetworkAccess: 'Enabled' - } } } -resource mysqlDatabase 'Microsoft.DBforMySQL/flexibleServers/databases@2024-12-01-preview' = { - parent: mysqlServer + resource mysqlDatabase 'databases' = { name: database properties: { charset: 'utf8' collation: 'utf8_general_ci' } } +} + output result object = { values: { From 479a4c09a41513594abf8898080c4cfd7f149d4b Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 13 Oct 2025 12:29:56 +0200 Subject: [PATCH 36/39] Updated resource API version Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index 3e33ac9f..ea667cfd 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -39,7 +39,7 @@ var port = 3306 @secure() param root_password string = uniqueString(context.resource.id, newGuid()) -resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2024-12-01-preview' = { +resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2024-12-30' = { name: uniqueName location: location tags: union(tags, radiusTags) From 87fe77ad2ec468a7c3d2c77a89927f14c07c52e5 Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 13 Oct 2025 12:31:20 +0200 Subject: [PATCH 37/39] Added second factor to make resource name more unique Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index ea667cfd..87ea96ef 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -30,7 +30,7 @@ var radiusTags = { var location string = resourceGroup().location @description('Unique name for the MySQL deployment and service.') -var uniqueName = 'mysql-${uniqueString(context.resource.id)}' +var uniqueName = 'mysql-${uniqueString(context.resource.id, resourceGroup().id)}' @description('The port the MySQL server listens on.') var port = 3306 From 93f2ec94d88ad13fb9a3b0a401bf51e6a3b92f7e Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 13 Oct 2025 12:32:18 +0200 Subject: [PATCH 38/39] Corrected formatting Signed-off-by: Andrew Matveychuk --- .../bicep/azure-database-for-mysql.bicep | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep index 87ea96ef..48746610 100644 --- a/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep +++ b/Data/mySqlDatabases/recipes/azure-database-for-mysql/bicep/azure-database-for-mysql.bicep @@ -58,17 +58,17 @@ resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2024-12-30' = { } network: { publicNetworkAccess: 'Enabled' + } } -} resource mysqlDatabase 'databases' = { - name: database - properties: { - charset: 'utf8' - collation: 'utf8_general_ci' + name: database + properties: { + charset: 'utf8' + collation: 'utf8_general_ci' + } } } -} output result object = { From 4c7c2833f9bdac758e82cc672c3d075fd96276ff Mon Sep 17 00:00:00 2001 From: Andrew Matveychuk Date: Mon, 13 Oct 2025 12:32:58 +0200 Subject: [PATCH 39/39] Converted type description to Markdown Signed-off-by: Andrew Matveychuk --- Data/mySqlDatabases/mySqlDatabases.yaml | 64 ++++++++++++++----------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/Data/mySqlDatabases/mySqlDatabases.yaml b/Data/mySqlDatabases/mySqlDatabases.yaml index 90f96190..b042664c 100644 --- a/Data/mySqlDatabases/mySqlDatabases.yaml +++ b/Data/mySqlDatabases/mySqlDatabases.yaml @@ -2,52 +2,58 @@ namespace: Radius.Data types: mySqlDatabases: description: | - The Radius.Data/mySqlDatabases Resource Type deploys a MySQL database. To deploy a new MySQL database, add the mySqlDatabases resource to the application definition Bicep file. + # Radius.Data/mySqlDatabases + The **Radius.Data/mySqlDatabases** Resource Type deploys a MySQL database. To deploy a new MySQL database, add the mySqlDatabases resource to the application definition Bicep file: + + ```bicep extension radius param environment string resource myApplication 'Applications.Core/applications@2023-10-01-preview' = { ... } resource database 'Radius.Data/mySqlDatabases@2025-08-01-preview' = { - name: 'database' - properties: { - application: myApplication.id - environment: environment - } + name: 'database' + properties: { + application: myApplication.id + environment: environment + } } + ``` - To connect your container to the database, create a connection from the Container resource to the database as shown below. + To connect your container to the database, create a connection from the Container resource to the database as shown below: + ```bicep resource frontend 'Applications.Core/containers@2023-10-01-preview' = { - name: 'frontend' - properties: { - application: myApplication.id - environment: environment - container: { - image: 'frontend:1.25' - ports: { - web: { - containerPort: 8080 + name: 'frontend' + properties: { + application: myApplication.id + environment: environment + container: { + image: 'frontend:1.25' + ports: { + web: { + containerPort: 8080 + } + } + } + connections: { + mysqldb: { + source: database.id + } } - } - } - connections: { - mysqldb: { - source: database.id - } } - } } + ``` The connection automatically injects environment variables into the container for all properties from the database. The environment variables are named `CONNECTION__`. In this example, the connection name is `mysqldb` so the environment variables will be: - CONNECTION_MYSQLDB_DATABASE - CONNECTION_MYSQLDB_USERNAME - CONNECTION_MYSQLDB_PASSWORD - CONNECTION_MYSQLDB_VERSION - CONNECTION_MYSQLDB_HOST - CONNECTION_MYSQLDB_PORT + * `CONNECTION_MYSQLDB_DATABASE` + * `CONNECTION_MYSQLDB_USERNAME` + * `CONNECTION_MYSQLDB_PASSWORD` + * `CONNECTION_MYSQLDB_VERSION` + * `CONNECTION_MYSQLDB_HOST` + * `CONNECTION_MYSQLDB_PORT` apiVersions: '2025-08-01-preview':