You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: eng/design-notes/extensibility/2026-04-automated-default-resource-type-registration.md
+28-21Lines changed: 28 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -47,12 +47,12 @@ This eliminates the need to copy files between repositories, ensures schemas sta
47
47
A platform engineer creates a new resource type `Radius.Networking/loadBalancers` in `resource-types-contrib`. To make it a default in Radius:
48
48
49
49
1. They add the YAML manifest at `Networking/loadBalancers/loadBalancers.yaml`.
50
-
2. They add the file path to `defaults.yaml`:
50
+
2. They add the resource type to `defaults.yaml`:
51
51
```yaml
52
52
defaultRegistration:
53
-
- Networking/loadBalancers/loadBalancers.yaml
53
+
- Radius.Networking/loadBalancers
54
54
```
55
-
3. They run `go generate` and commit `defaults.yaml` along with the auto-generated `manifests_gen.go` (which contains the `//go:embed` directives that tell the Go compiler which files to embed in the binary).
55
+
3. They run `go generate` and commit `defaults.yaml` along with the auto-generated `manifests_gen.go` (which contains the `//go:embed` directives that tell the Go compiler which files to embed in the binary). `gen_embed.go` resolves each resource type name to its corresponding file path by scanning the directory tree.
56
56
4. A Radius maintainer manually bumps the dependency by running `go get -u github.com/radius-project/resource-types-contrib` in the `radius` repository and merging the resulting `go.mod` change. Since `resource-types-contrib` does not have tagged releases today, Go resolves a pseudo-version based on the latest commit (e.g., `v0.0.0-20260408153021-abc123def456`).
57
57
58
58
#### Platform engineer updates a resource type schema
@@ -72,7 +72,7 @@ The design introduces `resource-types-contrib` as a Go module dependency of `rad
72
72
At startup, the UCP initializer service:
73
73
1. Reads `defaults.yaml` from the embedded filesystem to discover which manifests to load.
74
74
2. Parses each listed manifest, validates its schema, and merges manifests sharing a namespace into a single resource provider.
75
-
3. Registers the merged resource providers with UCP.
75
+
3. Registers the merged resource providers directly to the database, consistent with the existing startup registration path.
76
76
4. Proceeds to register any additional directory-based manifests as before.
77
77
78
78
The `location` field is intentionally omitted from `resource-types-contrib` manifests. When a manifest has no `location`, UCP's existing fallback mechanism routes requests to `DefaultDownstreamEndpoint` (dynamic-rp), which is the correct handler for all UDT-based resource types.
@@ -83,7 +83,7 @@ The `location` field is intentionally omitted from `resource-types-contrib` mani
│ defaults.yaml ─── lists types ───► go generate │
87
87
│ │ │
88
88
│ Compute/containers/containers.yaml ▼ │
89
89
│ Compute/routes/routes.yaml manifests_gen.go │
@@ -142,7 +142,7 @@ Add a `defaultRegistration` boolean field to each manifest YAML and to the `Reso
142
142
143
143
#### Option 2: Central `defaults.yaml` + `go generate` (Proposed)
144
144
145
-
A `defaults.yaml` file at the repo root lists which manifest paths should be default-registered. A `go generate` script reads this file and produces `manifests_gen.go` with `//go:embed` directives for exactly those files (plus `defaults.yaml` itself). At runtime, `RegisterFS` reads `defaults.yaml` from the embedded FS to know which paths to load.
145
+
A `defaults.yaml` file at the repo root lists which resource types should be default-registered using canonical `<namespace>/<typeName>` names. Running `go generate` invokes `gen_embed.go`, which reads this file, resolves each name to its corresponding manifest file path, and produces `manifests_gen.go` with `//go:embed` directives for exactly those files (plus `defaults.yaml` itself). At runtime, `RegisterFS` reads `defaults.yaml` from the embedded FS to know which paths to load.
146
146
147
147
##### Advantages
148
148
@@ -170,37 +170,40 @@ A `defaults.yaml` file at the repo root lists which manifest paths should be def
170
170
| File | Purpose |
171
171
|---|---|
172
172
| `go.mod` | Makes the repository a Go module (`github.com/radius-project/resource-types-contrib`). |
173
-
| `defaults.yaml` | Central list of manifest paths for default registration. |
174
-
| `gen_embed.go` | `go generate` script that reads `defaults.yaml` and produces `manifests_gen.go`. Build-tagged `//go:build ignore`. |
173
+
| `defaults.yaml` | Central list of resource types for default registration, using canonical `<namespace>/<typeName>` names. |
174
+
| `gen_embed.go` | Invoked by `go generate`. Reads `defaults.yaml`, resolves each resource type name to its file path, and produces `manifests_gen.go`. Build-tagged `//go:build ignore`. |
175
175
| `manifests.go` | Contains `//go:generate go run gen_embed.go` directive and package documentation. |
176
176
| `manifests_gen.go` | **Generated**. Contains `//go:embed` directives for `defaults.yaml` and each listed manifest. Exports `DefaultManifests embed.FS`. |
`gen_embed.go` resolves each entry to a file path using the convention: strip the `Radius.` prefix from the namespace, then `<namespace>/<typeName>/<typeName>.yaml` (e.g., `Radius.Compute/containers` resolves to `Compute/containers/containers.yaml`). If a file does not exist at the resolved path, `go generate` fails immediately.
190
+
189
191
**Manifest YAML files** remain unchanged: no `location` field, no `defaultRegistration` field. They contain only `namespace` and `types`.
190
192
191
193
#### UCP
192
194
193
195
**`pkg/cli/manifest/registermanifest.go`**: New `RegisterFS` function:
194
-
- Reads `defaults.yaml` from the provided `fs.FS` to get the list of manifest file paths.
195
-
- For each path, reads and parses the manifest using the existing `ReadBytes` function.
196
+
- Reads `defaults.yaml` from the provided `fs.FS` to get the list of resource type names.
197
+
- For each entry, resolves the resource type name to the corresponding embedded manifest file path.
198
+
- Reads and parses the manifest using the existing `ReadBytes` function.
196
199
- Validates schemas using the existing `validateManifestSchemas` function.
197
200
- Merges manifests sharing a namespace (e.g., three `Radius.Compute` files) into a single `ResourceProvider` with all types under one `Types` map.
198
-
-Registers each merged provider using the existing `RegisterResourceProvider` function.
201
+
-Returns the merged providers to the initializer for direct database registration.
199
202
200
203
**`pkg/ucp/initializer/service.go`** (updated):
201
204
-`NewService` accepts an additional `fs.FS` parameter for embedded manifests.
202
-
-`Run`calls `manifest.RegisterFS`for embedded manifests **before**`manifest.RegisterDirectory` for directory-based manifests.
203
-
- If both embedded and directory manifests exist, both are registered. Directory-based manifests can override embedded ones (last-write-wins via UCP's `CreateOrUpdate`).
205
+
-`Run`processes embedded manifests by calling `RegisterFS`to parse and merge them, then registers each merged provider using `registerResourceProviderDirect` (direct database writes), consistent with how directory-based manifests are already registered at startup. This avoids HTTP round-trips, async operation queues, and polling.
206
+
- If both embedded and directory manifests exist, both are registered. Directory-based manifests can override embedded ones (last-write-wins via direct database save).
204
207
205
208
**`pkg/ucp/server/server.go`** (updated):
206
209
- Imports `resource-types-contrib` and passes `resourcetypes.DefaultManifests` to `initializer.NewService`.
@@ -220,8 +223,7 @@ Remaining files ( `radius_core.yaml`, `microsoft_resources.yaml`) stay because t
220
223
| Manifest YAML has invalid syntax |`ReadBytes` returns parse error. Startup fails with the specific file identified. |
221
224
| Manifest schema validation fails |`validateManifestSchemas` returns error. Startup fails with the specific file identified. |
222
225
|`defaults.yaml` is empty (no entries) |`RegisterFS` logs a message and returns nil. Startup continues with directory-based manifests only. |
223
-
| UCP not reachable at startup | Existing `waitForServer` timeout behavior. No change from current behavior. |
224
-
| 409 conflict during registration | Existing retry logic with exponential backoff. No change from current behavior. |
226
+
|`rad upgrade` introduces new default resource types | New types are registered via direct database save on startup. Existing types are updated. No error expected. |
225
227
226
228
## Test plan
227
229
@@ -236,6 +238,7 @@ Remaining files ( `radius_core.yaml`, `microsoft_resources.yaml`) stay because t
236
238
2.**Integration tests**:
237
239
- Existing `Test_ResourceProvider_RegisterManifests` continues to work (tests directory-based registration).
238
240
- New test that passes an `embed.FS` to `NewService` and verifies the resource provider is registered correctly.
241
+
- Test `rad upgrade` scenario: register an initial set of embedded types, then simulate an upgrade with an updated `embed.FS` containing an additional default type. Verify the new type is registered and existing types are updated without errors.
239
242
240
243
3.**CI validation for `manifests_gen.go`**:
241
244
- In `resource-types-contrib` CI: run `go generate` and verify no diff to ensure the generated file is up to date.
@@ -394,6 +397,10 @@ update-resource-types:
394
397
go mod tidy
395
398
```
396
399
400
+
### Ensuring the dependency is kept up to date
401
+
402
+
Until tagged releases and Dependabot automation are in place (see Follow-up Item #3), bumping the `resource-types-contrib` dependency in `radius` is a manual step. To ensure this is not forgotten, include a step in the Radius release checklist to run `make update-resource-types` and verify the latest resource type schemas are included before each release.
403
+
397
404
## Open Questions
398
405
399
406
1.**`gogenerate`enforcement**: Should `resource-types-contrib` CI block merges if `manifests_gen.go` is out of date, or should CI auto-regenerate and commit?
0 commit comments