From 647c0c7f34151e248431a9b8c233f2f9200bdc28 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 9 Feb 2024 19:01:35 -0600 Subject: [PATCH 1/4] Update Namespace.ValidateNamespace to add workspace to arguments (#7154) Signed-off-by: Josh # Description in order for the non current context to be used by ValidateNamespaces so that it can create namespaces in the workspaces kubernetes context we need to pass in the workspace and then use workspace.KuberneteContext() to look up the correct context. ## Type of change This pull request fixes a bug in Radius and has an approved issue (issue link required). Fixes: #5698 --------- Signed-off-by: Josh --- pkg/cli/cmd/env/create/create.go | 2 +- pkg/cli/cmd/env/create/create_test.go | 4 ++-- pkg/cli/cmd/env/namespace/mock_namespace.go | 9 +++++---- pkg/cli/cmd/env/namespace/namespace.go | 13 ++++++++++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/pkg/cli/cmd/env/create/create.go b/pkg/cli/cmd/env/create/create.go index c185402c42..f0e38879c5 100644 --- a/pkg/cli/cmd/env/create/create.go +++ b/pkg/cli/cmd/env/create/create.go @@ -141,7 +141,7 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { return err } - err = r.NamespaceInterface.ValidateNamespace(cmd.Context(), r.Namespace) + err = r.NamespaceInterface.ValidateNamespace(cmd.Context(), r.Namespace, *r.Workspace) if err != nil { return err } diff --git a/pkg/cli/cmd/env/create/create_test.go b/pkg/cli/cmd/env/create/create_test.go index 87e9f25e06..3273946df1 100644 --- a/pkg/cli/cmd/env/create/create_test.go +++ b/pkg/cli/cmd/env/create/create_test.go @@ -271,13 +271,13 @@ func createMocksWithInvalidResourceGroup(namespaceClient *namespace.MockInterfac func createValidateNamespaceSuccess(namespaceClient *namespace.MockInterface) { namespaceClient.EXPECT(). - ValidateNamespace(gomock.Any(), "testingenv"). + ValidateNamespace(gomock.Any(), "testingenv", gomock.Any()). Return(nil).Times(1) } func createValidateNamespaceError(namespaceClient *namespace.MockInterface) { namespaceClient.EXPECT(). - ValidateNamespace(gomock.Any(), gomock.Any()). + ValidateNamespace(gomock.Any(), gomock.Any(), gomock.Any()). Return(fmt.Errorf("failed to create namespace")).Times(1) } diff --git a/pkg/cli/cmd/env/namespace/mock_namespace.go b/pkg/cli/cmd/env/namespace/mock_namespace.go index f03b7878f0..756add1801 100644 --- a/pkg/cli/cmd/env/namespace/mock_namespace.go +++ b/pkg/cli/cmd/env/namespace/mock_namespace.go @@ -9,6 +9,7 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" + workspaces "github.com/radius-project/radius/pkg/cli/workspaces" ) // MockInterface is a mock of Interface interface. @@ -35,15 +36,15 @@ func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { } // ValidateNamespace mocks base method. -func (m *MockInterface) ValidateNamespace(arg0 context.Context, arg1 string) error { +func (m *MockInterface) ValidateNamespace(arg0 context.Context, arg1 string, arg2 workspaces.Workspace) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateNamespace", arg0, arg1) + ret := m.ctrl.Call(m, "ValidateNamespace", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // ValidateNamespace indicates an expected call of ValidateNamespace. -func (mr *MockInterfaceMockRecorder) ValidateNamespace(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockInterfaceMockRecorder) ValidateNamespace(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNamespace", reflect.TypeOf((*MockInterface)(nil).ValidateNamespace), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNamespace", reflect.TypeOf((*MockInterface)(nil).ValidateNamespace), arg0, arg1, arg2) } diff --git a/pkg/cli/cmd/env/namespace/namespace.go b/pkg/cli/cmd/env/namespace/namespace.go index ac983ef0da..5fb35e43e6 100644 --- a/pkg/cli/cmd/env/namespace/namespace.go +++ b/pkg/cli/cmd/env/namespace/namespace.go @@ -19,12 +19,14 @@ package namespace import ( "context" + "github.com/radius-project/radius/pkg/cli/clierrors" "github.com/radius-project/radius/pkg/cli/kubernetes" + "github.com/radius-project/radius/pkg/cli/workspaces" ) //go:generate mockgen -destination=./mock_namespace.go -package=namespace -self_package github.com/radius-project/radius/pkg/cli/cmd/env/namespace github.com/radius-project/radius/pkg/cli/cmd/env/namespace Interface type Interface interface { - ValidateNamespace(ctx context.Context, namespace string) error + ValidateNamespace(ctx context.Context, namespace string, workspace workspaces.Workspace) error } type Impl struct { @@ -35,8 +37,13 @@ type Impl struct { // ValidateNamespace creates a Kubernetes client and checks if the given namespace exists. If it does not exist, creates it. // If unsuccessful, returns an error. -func (i *Impl) ValidateNamespace(ctx context.Context, namespace string) error { - client, _, err := kubernetes.NewClientset("") +func (i *Impl) ValidateNamespace(ctx context.Context, namespace string, workspace workspaces.Workspace) error { + // get the current kubernetes context from the workspace + kubernetesContext, hasContext := workspace.KubernetesContext() + if !hasContext { + return clierrors.Message("no kubernetes context found in the current workspace") + } + client, _, err := kubernetes.NewClientset(kubernetesContext) if err != nil { return err } From c52aa0034c335fd2374ae4fe8214d937de0197fd Mon Sep 17 00:00:00 2001 From: Young Bu Park Date: Thu, 15 Feb 2024 17:59:16 -0800 Subject: [PATCH 2/4] Set go version to 1.21.7 (#7179) # Description Set go version to 1.21.7 because controller-gen throws nil error with go 1.22 ``` => Generating CRDs for ucp.dev... controller-gen object paths=./pkg/ucp/store/apiserverstore/api/ucp.dev/v1alpha1/... object:headerFile=./boilerplate.go.txt panic: runtime error: invalid memory address or nil pointer dereference [recovered] panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xa0117e] goroutine 81 [running]: go/types.(*Checker).handleBailout(0xc0002e6600, 0xc000459d40) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/check.go:367 +0x88 panic({0xbb2600?, 0x128ed00?}) /opt/hostedtoolcache/go/1.22.0/x64/src/runtime/panic.go:770 +0x132 go/types.(*StdSizes).Sizeof(0x0, {0xda56d8, 0x1297540}) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/sizes.go:228 +0x31e go/types.(*Config).sizeof(...) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/sizes.go:333 go/types.representableConst.func1({0xda56d8?, 0x1297540?}) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/const.go:76 +0x9e go/types.representableConst({0xdab9f8, 0x12635a0}, 0xc0002e6600, 0x1297540, 0x0) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/const.go:92 +0x192 go/types.(*Checker).arrayLength(0xc0002e6600, {0xda9d08, 0xc00093cbc0?}) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/typexpr.go:510 +0x2d3 go/types.(*Checker).typInternal(0xc0002e6600, {0xda8358, 0xc000936f60}, 0x0) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/typexpr.go:299 +0x49d go/types.(*Checker).definedType(0xc0002e6600, {0xda8358, 0xc000936f60}, 0xc000459328?) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/typexpr.go:180 +0x37 go/types.(*Checker).varType(0xc0002e6600, {0xda8358, 0xc000936f60}) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/typexpr.go:145 +0x25 go/types.(*Checker).structType(0xc0002e6600, 0xc00095e660, 0xc00095e660?) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/struct.go:113 +0x19f go/types.(*Checker).typInternal(0xc0002e6600, {0xda82c8, 0xc000935728}, 0xc00095b590) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/typexpr.go:316 +0x1345 go/types.(*Checker).definedType(0xc0002e6600, {0xda82c8, 0xc000935728}, 0xc7a5e2?) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/typexpr.go:180 +0x37 go/types.(*Checker).typeDecl(0xc0002e6600, 0xc00095b590, 0xc0009389c0, 0x0) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/decl.go:615 +0x44d go/types.(*Checker).objDecl(0xc0002e6600, {0xdb0e58, 0xc00095b590}, 0x0) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/decl.go:197 +0xa7f go/types.(*Checker).packageObjects(0xc0002e6600) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/resolver.go:681 +0x425 go/types.(*Checker).checkFiles(0xc0002e6600, {0xc000580ed0, 0x3, 0x3}) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/check.go:408 +0x1a5 go/types.(*Checker).Files(...) /opt/hostedtoolcache/go/1.22.0/x64/src/go/types/check.go:372 sigs.k8s.io/controller-tools/pkg/loader.(*loader).typeCheck(0xc0003eb080, 0xc0004[2008](https://github.com/radius-project/radius/actions/runs/7924253811/job/21635483458?pr=7179#step:13:2009)0) /home/runner/go/pkg/mod/sigs.k8s.io/controller-tools@v0.9.1/pkg/loader/loader.go:286 +0x36a sigs.k8s.io/controller-tools/pkg/loader.(*Package).NeedTypesInfo(0xc000420080) /home/runner/go/pkg/mod/sigs.k8s.io/controller-tools@v0.9.1/pkg/loader/loader.go:99 +0x39 sigs.k8s.io/controller-tools/pkg/loader.(*TypeChecker).check(0xc0003b60c0, 0xc000420080) /home/runner/go/pkg/mod/sigs.k8s.io/controller-tools@v0.9.1/pkg/loader/refs.go:268 +0x2b7 sigs.k8s.io/controller-tools/pkg/loader.(*TypeChecker).check.func1(0x51?) /home/runner/go/pkg/mod/sigs.k8s.io/controller-tools@v0.9.1/pkg/loader/refs.go:262 +0x53 created by sigs.k8s.io/controller-tools/pkg/loader.(*TypeChecker).check in goroutine 9 /home/runner/go/pkg/mod/sigs.k8s.io/controller-tools@v0.9.1/pkg/loader/refs.go:260 +0x1c5 make: *** [build/generate.mk:65: generate-ucp-crd] Error 2 Error: Process completed with exit code 2. ``` ## Type of change - This pull request is a minor refactor, code cleanup, test improvement, or other maintenance task and doesn't change the functionality of Radius (issue link optional). Fixes: #issue_number Signed-off-by: Young Bu Park --- .github/workflows/build.yaml | 2 +- .github/workflows/functional-test.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/long-running-azure.yaml | 2 +- .github/workflows/publish-docs.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7d639144ed..8874d7d212 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -35,7 +35,7 @@ concurrency: env: # Go version to install - GOVER: '^1.21' + GOVER: '1.21.7' # gotestsum version - see: https://github.com/gotestyourself/gotestsum GOTESTSUMVERSION: 1.10.0 diff --git a/.github/workflows/functional-test.yaml b/.github/workflows/functional-test.yaml index d117acfb00..5ebe748620 100644 --- a/.github/workflows/functional-test.yaml +++ b/.github/workflows/functional-test.yaml @@ -31,7 +31,7 @@ on: env: # Go version - GOVER: '^1.21' + GOVER: '1.21.7' GOPROXY: https://proxy.golang.org # gotestsum version - see: https://github.com/gotestyourself/gotestsum diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index c6e1066494..b96210ebe8 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 env: - GOVER: '^1.21' + GOVER: '1.21.7' GOPROXY: https://proxy.golang.org HELM_CHARTS_DIR: deploy/Chart steps: diff --git a/.github/workflows/long-running-azure.yaml b/.github/workflows/long-running-azure.yaml index 841294cefd..f74d24f9a4 100644 --- a/.github/workflows/long-running-azure.yaml +++ b/.github/workflows/long-running-azure.yaml @@ -49,7 +49,7 @@ on: env: # Go version - GOVER: "^1.21" + GOVER: "1.21.7" GOPROXY: https://proxy.golang.org # gotestsum version - see: https://github.com/gotestyourself/gotestsum diff --git a/.github/workflows/publish-docs.yaml b/.github/workflows/publish-docs.yaml index 720431befa..aac8d718f7 100644 --- a/.github/workflows/publish-docs.yaml +++ b/.github/workflows/publish-docs.yaml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'radius-project/radius' env: - GOVER: '^1.21' + GOVER: '1.21.7' GOPRIVATE: github.com/radius-project steps: - name: Checkout radius repository From 275b861093057c9ded559b2ad36487647cab81a1 Mon Sep 17 00:00:00 2001 From: Vishwanath Hiremath <100623239+vishwahiremat@users.noreply.github.com> Date: Wed, 21 Feb 2024 10:46:10 -0800 Subject: [PATCH 3/4] updating patch api def for applications resource (#7182) # Description Updated patch api def on typespec for applications resource. ## Type of change - This pull request fixes a bug in Radius and has an approved issue (issue link required). - This pull request is a minor refactor, code cleanup, test improvement, or other maintenance task and doesn't change the functionality of Radius (issue link optional). Fixes: #issue_number Signed-off-by: Vishwanath Hiremath --- .../v20231001preview/zz_generated_models.go | 15 ++-------- .../zz_generated_models_serde.go | 29 ++----------------- .../preview/2023-10-01-preview/openapi.json | 26 +++-------------- typespec/Applications.Core/applications.tsp | 2 +- 4 files changed, 11 insertions(+), 61 deletions(-) diff --git a/pkg/corerp/api/v20231001preview/zz_generated_models.go b/pkg/corerp/api/v20231001preview/zz_generated_models.go index 73b3f0a979..0170d202ac 100644 --- a/pkg/corerp/api/v20231001preview/zz_generated_models.go +++ b/pkg/corerp/api/v20231001preview/zz_generated_models.go @@ -117,20 +117,11 @@ type ApplicationResourceUpdate struct { // ApplicationResourceUpdateProperties - The updatable properties of the ApplicationResource. type ApplicationResourceUpdateProperties struct { - // The compute resource used by application environment. - Compute EnvironmentComputeUpdateClassification + // Fully qualified resource ID for the environment that the application is linked to + Environment *string - // The environment extension. + // The application extension. Extensions []ExtensionClassification - - // Cloud providers configuration for the environment. - Providers *ProvidersUpdate - - // Specifies Recipes linked to the Environment. - Recipes map[string]map[string]RecipePropertiesUpdateClassification - - // Simulated environment. - Simulated *bool } // AzureKeyVaultVolumeProperties - Represents Azure Key Vault Volume properties diff --git a/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go b/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go index 6446564248..c1b39b8004 100644 --- a/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go +++ b/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go @@ -309,11 +309,8 @@ func (a *ApplicationResourceUpdate) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaller interface for type ApplicationResourceUpdateProperties. func (a ApplicationResourceUpdateProperties) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) - populate(objectMap, "compute", a.Compute) + populate(objectMap, "environment", a.Environment) populate(objectMap, "extensions", a.Extensions) - populate(objectMap, "providers", a.Providers) - populate(objectMap, "recipes", a.Recipes) - populate(objectMap, "simulated", a.Simulated) return json.Marshal(objectMap) } @@ -326,32 +323,12 @@ func (a *ApplicationResourceUpdateProperties) UnmarshalJSON(data []byte) error { for key, val := range rawMsg { var err error switch key { - case "compute": - a.Compute, err = unmarshalEnvironmentComputeUpdateClassification(val) + case "environment": + err = unpopulate(val, "Environment", &a.Environment) delete(rawMsg, key) case "extensions": a.Extensions, err = unmarshalExtensionClassificationArray(val) delete(rawMsg, key) - case "providers": - err = unpopulate(val, "Providers", &a.Providers) - delete(rawMsg, key) - case "recipes": - var recipesRaw map[string]json.RawMessage - if err = json.Unmarshal(val, &recipesRaw); err != nil { - return err - } - recipes := map[string]map[string]RecipePropertiesUpdateClassification{} - for k1, v1 := range recipesRaw { - recipes[k1], err = unmarshalRecipePropertiesUpdateClassificationMap(v1) - if err != nil { - return fmt.Errorf("unmarshalling type %T: %v", a, err) - } - } - a.Recipes = recipes - delete(rawMsg, key) - case "simulated": - err = unpopulate(val, "Simulated", &a.Simulated) - delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", a, err) diff --git a/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json b/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json index b251b023ec..e3bd250f4e 100644 --- a/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json +++ b/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json @@ -2723,31 +2723,13 @@ "type": "object", "description": "The updatable properties of the ApplicationResource.", "properties": { - "compute": { - "$ref": "#/definitions/EnvironmentComputeUpdate", - "description": "The compute resource used by application environment." - }, - "providers": { - "$ref": "#/definitions/ProvidersUpdate", - "description": "Cloud providers configuration for the environment." - }, - "simulated": { - "type": "boolean", - "description": "Simulated environment." - }, - "recipes": { - "type": "object", - "description": "Specifies Recipes linked to the Environment.", - "additionalProperties": { - "additionalProperties": { - "$ref": "#/definitions/RecipePropertiesUpdate" - }, - "type": "object" - } + "environment": { + "type": "string", + "description": "Fully qualified resource ID for the environment that the application is linked to" }, "extensions": { "type": "array", - "description": "The environment extension.", + "description": "The application extension.", "items": { "$ref": "#/definitions/Extension" }, diff --git a/typespec/Applications.Core/applications.tsp b/typespec/Applications.Core/applications.tsp index f3ac9a2462..da13698204 100644 --- a/typespec/Applications.Core/applications.tsp +++ b/typespec/Applications.Core/applications.tsp @@ -142,7 +142,7 @@ interface Applications { update is ArmResourcePatchSync< ApplicationResource, - EnvironmentProperties, + ApplicationProperties, UCPBaseParameters >; From 68855744c2ad0326ef30dfd1d4d8df2e7d6c999b Mon Sep 17 00:00:00 2001 From: Vishwanath Hiremath <100623239+vishwahiremat@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:31:12 -0800 Subject: [PATCH 4/4] Adding changes to extend secret stores scope to global (#7155) # Description - Adding changes to support global scope - Remove appliction as a requred property - Create namespace provided by user if not exists - Adding unit tests Design doc: https://github.com/radius-project/design-notes/pull/38 ## Type of change - This pull request adds or changes features of Radius and has an approved issue (issue link required). - This pull request is a minor refactor, code cleanup, test improvement, or other maintenance task and doesn't change the functionality of Radius (issue link optional). Fixes: https://github.com/radius-project/radius/issues/7030 --------- Signed-off-by: Vishwanath Hiremath Signed-off-by: Karishma Chawla Co-authored-by: Karishma Chawla --- .../2023-10-01-preview/types.json | 2 +- .../v20231001preview/zz_generated_models.go | 6 +- .../controller/secretstores/kubernetes.go | 17 ++- .../secretstores/kubernetes_test.go | 112 +++++++++++++++++- .../secretstores_datamodel_global_scope.json | 37 ++++++ ...datamodel_global_scope_empty_resource.json | 36 ++++++ ...tamodel_global_scope_invalid_resource.json | 37 ++++++ pkg/rp/v1/types.go | 5 + pkg/rp/v1/types_test.go | 35 ++++++ ...cretStores_CreateOrUpdate_GlobalScope.json | 49 ++++++++ .../preview/2023-10-01-preview/openapi.json | 4 +- ...cretStores_CreateOrUpdate_GlobalScope.json | 49 ++++++++ typespec/Applications.Core/secretstores.tsp | 2 +- typespec/radius/v1/resources.tsp | 17 +++ 14 files changed, 397 insertions(+), 11 deletions(-) create mode 100644 pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope.json create mode 100644 pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_empty_resource.json create mode 100644 pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_invalid_resource.json create mode 100644 swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/examples/SecretStores_CreateOrUpdate_GlobalScope.json create mode 100644 typespec/Applications.Core/examples/2023-10-01-preview/SecretStores_CreateOrUpdate_GlobalScope.json diff --git a/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.json b/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.json index 2655f064ba..378210d4ef 100644 --- a/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.json +++ b/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.json @@ -1 +1 @@ -[{"1":{"Kind":1}},{"1":{"Kind":2}},{"1":{"Kind":3}},{"1":{"Kind":4}},{"1":{"Kind":5}},{"1":{"Kind":6}},{"1":{"Kind":7}},{"1":{"Kind":8}},{"6":{"Value":"Applications.Core/applications"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/applications","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":8,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":9,"Flags":10,"Description":"The resource api version"},"properties":{"Type":11,"Flags":1,"Description":"Application properties"},"tags":{"Type":46,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"ApplicationProperties","Properties":{"provisioningState":{"Type":19,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"extensions":{"Type":34,"Flags":0,"Description":"The application extension."},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[12,13,14,15,16,17,18]}},{"7":{"Name":"Extension","Discriminator":"kind","BaseProperties":{},"Elements":{"daprSidecar":21,"kubernetesMetadata":26,"kubernetesNamespace":30,"manualScaling":32}}},{"2":{"Name":"DaprSidecarExtension","Properties":{"appPort":{"Type":3,"Flags":0,"Description":"The Dapr appPort. Specifies the internal listening port for the application to handle requests from the Dapr sidecar."},"appId":{"Type":4,"Flags":1,"Description":"The Dapr appId. Specifies the identifier used by Dapr for service invocation."},"config":{"Type":4,"Flags":0,"Description":"Specifies the Dapr configuration to use for the resource."},"protocol":{"Type":24,"Flags":0,"Description":"The Dapr sidecar extension protocol"},"kind":{"Type":25,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"6":{"Value":"http"}},{"6":{"Value":"grpc"}},{"5":{"Elements":[22,23]}},{"6":{"Value":"daprSidecar"}},{"2":{"Name":"KubernetesMetadataExtension","Properties":{"annotations":{"Type":27,"Flags":0,"Description":"Annotations to be applied to the Kubernetes resources output by the resource"},"labels":{"Type":28,"Flags":0,"Description":"Labels to be applied to the Kubernetes resources output by the resource"},"kind":{"Type":29,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"2":{"Name":"KubernetesMetadataExtensionAnnotations","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"KubernetesMetadataExtensionLabels","Properties":{},"AdditionalProperties":4}},{"6":{"Value":"kubernetesMetadata"}},{"2":{"Name":"KubernetesNamespaceExtension","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace of the application environment."},"kind":{"Type":31,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"6":{"Value":"kubernetesNamespace"}},{"2":{"Name":"ManualScalingExtension","Properties":{"replicas":{"Type":3,"Flags":1,"Description":"Replica count."},"kind":{"Type":33,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"6":{"Value":"manualScaling"}},{"3":{"ItemType":20}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":36,"Flags":0,"Description":"Represents backing compute resource"},"recipe":{"Type":43,"Flags":2,"Description":"Recipe status at deployment time for a resource."},"outputResources":{"Type":45,"Flags":0,"Description":"Properties of an output resource"}}}},{"7":{"Name":"EnvironmentCompute","Discriminator":"kind","BaseProperties":{"resourceId":{"Type":4,"Flags":0,"Description":"The resource id of the compute resource for application environment."},"identity":{"Type":37,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":41}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":40,"Flags":1,"Description":"IdentitySettingKind is the kind of supported external identity setting"},"oidcIssuer":{"Type":4,"Flags":0,"Description":"The URI for your compute platform's OIDC issuer"},"resource":{"Type":4,"Flags":0,"Description":"The resource ID of the provisioned identity"}}}},{"6":{"Value":"undefined"}},{"6":{"Value":"azure.com.workload"}},{"5":{"Elements":[38,39]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":42,"Flags":1,"Description":"Discriminator property for EnvironmentCompute."}}}},{"6":{"Value":"kubernetes"}},{"2":{"Name":"RecipeStatus","Properties":{"templateKind":{"Type":4,"Flags":1,"Description":"TemplateKind is the kind of the recipe template used by the portable resource upon deployment."},"templatePath":{"Type":4,"Flags":1,"Description":"TemplatePath is the path of the recipe consumed by the portable resource upon deployment."},"templateVersion":{"Type":4,"Flags":0,"Description":"TemplateVersion is the version number of the template."}}}},{"2":{"Name":"OutputResource","Properties":{"localId":{"Type":4,"Flags":0,"Description":"The logical identifier scoped to the owning Radius resource. This is only needed or used when a resource has a dependency relationship. LocalIDs do not have any particular format or meaning beyond being compared to determine dependency relationships."},"id":{"Type":4,"Flags":0,"Description":"The UCP resource ID of the underlying resource."},"radiusManaged":{"Type":2,"Flags":0,"Description":"Determines whether Radius manages the lifecycle of the underlying resource."}}}},{"3":{"ItemType":44}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":52,"Flags":0,"Description":"The type of identity that created the resource."},"createdAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource creation (UTC)."},"lastModifiedBy":{"Type":4,"Flags":0,"Description":"The identity that last modified the resource."},"lastModifiedByType":{"Type":57,"Flags":0,"Description":"The type of identity that created the resource."},"lastModifiedAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource last modification (UTC)"}}}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[48,49,50,51]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[53,54,55,56]}},{"4":{"Name":"Applications.Core/applications@2023-10-01-preview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Core/containers"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/containers","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":59,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":60,"Flags":10,"Description":"The resource api version"},"properties":{"Type":62,"Flags":1,"Description":"Container properties"},"tags":{"Type":122,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"ContainerProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":70,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"container":{"Type":71,"Flags":1,"Description":"Definition of a container"},"connections":{"Type":108,"Flags":0,"Description":"Specifies a connection to another resource."},"identity":{"Type":37,"Flags":0,"Description":"IdentitySettings is the external identity setting."},"extensions":{"Type":109,"Flags":0,"Description":"Extensions spec of the resource"},"resourceProvisioning":{"Type":112,"Flags":0,"Description":"Specifies how the underlying service/resource is provisioned and managed. Available values are 'internal', where Radius manages the lifecycle of the resource internally, and 'manual', where a user manages the resource."},"resources":{"Type":114,"Flags":0,"Description":"A collection of references to resources associated with the container"},"restartPolicy":{"Type":118,"Flags":0,"Description":"Restart policy for the container"},"runtimes":{"Type":119,"Flags":0,"Description":"The properties for runtime configuration"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[63,64,65,66,67,68,69]}},{"2":{"Name":"Container","Properties":{"image":{"Type":4,"Flags":1,"Description":"The registry and image to download and run in your container"},"imagePullPolicy":{"Type":75,"Flags":0,"Description":"The image pull policy for the container"},"env":{"Type":76,"Flags":0,"Description":"environment"},"ports":{"Type":81,"Flags":0,"Description":"container ports"},"readinessProbe":{"Type":82,"Flags":0,"Description":"Properties for readiness/liveness probe"},"livenessProbe":{"Type":82,"Flags":0,"Description":"Properties for readiness/liveness probe"},"volumes":{"Type":101,"Flags":0,"Description":"container volumes"},"command":{"Type":102,"Flags":0,"Description":"Entrypoint array. Overrides the container image's ENTRYPOINT"},"args":{"Type":103,"Flags":0,"Description":"Arguments to the entrypoint. Overrides the container image's CMD"},"workingDir":{"Type":4,"Flags":0,"Description":"Working directory for the container"}}}},{"6":{"Value":"Always"}},{"6":{"Value":"IfNotPresent"}},{"6":{"Value":"Never"}},{"5":{"Elements":[72,73,74]}},{"2":{"Name":"ContainerEnv","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"ContainerPortProperties","Properties":{"containerPort":{"Type":3,"Flags":1,"Description":"The listening port number"},"protocol":{"Type":80,"Flags":0,"Description":"The protocol in use by the port"},"provides":{"Type":4,"Flags":0,"Description":"Specifies a route provided by this port"},"scheme":{"Type":4,"Flags":0,"Description":"Specifies the URL scheme of the communication protocol. Consumers can use the scheme to construct a URL. The value defaults to 'http' or 'https' depending on the port value"},"port":{"Type":3,"Flags":0,"Description":"Specifies the port that will be exposed by this container. Must be set when value different from containerPort is desired"}}}},{"6":{"Value":"TCP"}},{"6":{"Value":"UDP"}},{"5":{"Elements":[78,79]}},{"2":{"Name":"ContainerPorts","Properties":{},"AdditionalProperties":77}},{"7":{"Name":"HealthProbeProperties","Discriminator":"kind","BaseProperties":{"initialDelaySeconds":{"Type":3,"Flags":0,"Description":"Initial delay in seconds before probing for readiness/liveness"},"failureThreshold":{"Type":3,"Flags":0,"Description":"Threshold number of times the probe fails after which a failure would be reported"},"periodSeconds":{"Type":3,"Flags":0,"Description":"Interval for the readiness/liveness probe in seconds"},"timeoutSeconds":{"Type":3,"Flags":0,"Description":"Number of seconds after which the readiness/liveness probe times out. Defaults to 5 seconds"}},"Elements":{"exec":83,"httpGet":85,"tcp":88}}},{"2":{"Name":"ExecHealthProbeProperties","Properties":{"command":{"Type":4,"Flags":1,"Description":"Command to execute to probe readiness/liveness"},"kind":{"Type":84,"Flags":1,"Description":"Discriminator property for HealthProbeProperties."}}}},{"6":{"Value":"exec"}},{"2":{"Name":"HttpGetHealthProbeProperties","Properties":{"containerPort":{"Type":3,"Flags":1,"Description":"The listening port number"},"path":{"Type":4,"Flags":1,"Description":"The route to make the HTTP request on"},"headers":{"Type":86,"Flags":0,"Description":"Custom HTTP headers to add to the get request"},"kind":{"Type":87,"Flags":1,"Description":"Discriminator property for HealthProbeProperties."}}}},{"2":{"Name":"HttpGetHealthProbePropertiesHeaders","Properties":{},"AdditionalProperties":4}},{"6":{"Value":"httpGet"}},{"2":{"Name":"TcpHealthProbeProperties","Properties":{"containerPort":{"Type":3,"Flags":1,"Description":"The listening port number"},"kind":{"Type":89,"Flags":1,"Description":"Discriminator property for HealthProbeProperties."}}}},{"6":{"Value":"tcp"}},{"7":{"Name":"Volume","Discriminator":"kind","BaseProperties":{"mountPath":{"Type":4,"Flags":0,"Description":"The path where the volume is mounted"}},"Elements":{"ephemeral":91,"persistent":96}}},{"2":{"Name":"EphemeralVolume","Properties":{"managedStore":{"Type":94,"Flags":1,"Description":"The managed store for the ephemeral volume"},"kind":{"Type":95,"Flags":1,"Description":"Discriminator property for Volume."}}}},{"6":{"Value":"memory"}},{"6":{"Value":"disk"}},{"5":{"Elements":[92,93]}},{"6":{"Value":"ephemeral"}},{"2":{"Name":"PersistentVolume","Properties":{"permission":{"Type":99,"Flags":0,"Description":"The persistent volume permission"},"source":{"Type":4,"Flags":1,"Description":"The source of the volume"},"kind":{"Type":100,"Flags":1,"Description":"Discriminator property for Volume."}}}},{"6":{"Value":"read"}},{"6":{"Value":"write"}},{"5":{"Elements":[97,98]}},{"6":{"Value":"persistent"}},{"2":{"Name":"ContainerVolumes","Properties":{},"AdditionalProperties":90}},{"3":{"ItemType":4}},{"3":{"ItemType":4}},{"2":{"Name":"ConnectionProperties","Properties":{"source":{"Type":4,"Flags":1,"Description":"The source of the connection"},"disableDefaultEnvVars":{"Type":2,"Flags":0,"Description":"default environment variable override"},"iam":{"Type":105,"Flags":0,"Description":"IAM properties"}}}},{"2":{"Name":"IamProperties","Properties":{"kind":{"Type":106,"Flags":1,"Description":"The kind of IAM provider to configure"},"roles":{"Type":107,"Flags":0,"Description":"RBAC permissions to be assigned on the source resource"}}}},{"6":{"Value":"azure"}},{"3":{"ItemType":4}},{"2":{"Name":"ContainerPropertiesConnections","Properties":{},"AdditionalProperties":104}},{"3":{"ItemType":20}},{"6":{"Value":"internal"}},{"6":{"Value":"manual"}},{"5":{"Elements":[110,111]}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":113}},{"6":{"Value":"Always"}},{"6":{"Value":"OnFailure"}},{"6":{"Value":"Never"}},{"5":{"Elements":[115,116,117]}},{"2":{"Name":"RuntimesProperties","Properties":{"kubernetes":{"Type":120,"Flags":0,"Description":"The runtime configuration properties for Kubernetes"}}}},{"2":{"Name":"KubernetesRuntimeProperties","Properties":{"base":{"Type":4,"Flags":0,"Description":"The serialized YAML manifest which represents the base Kubernetes resources to deploy, such as Deployment, Service, ServiceAccount, Secrets, and ConfigMaps."},"pod":{"Type":121,"Flags":0,"Description":"A strategic merge patch that will be applied to the PodSpec object when this container is being deployed."}}}},{"2":{"Name":"KubernetesPodSpec","Properties":{},"AdditionalProperties":0}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/containers@2023-10-01-preview","ScopeType":0,"Body":61}},{"6":{"Value":"Applications.Core/environments"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/environments","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":124,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":125,"Flags":10,"Description":"The resource api version"},"properties":{"Type":127,"Flags":1,"Description":"Environment properties"},"tags":{"Type":147,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"EnvironmentProperties","Properties":{"provisioningState":{"Type":135,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"compute":{"Type":36,"Flags":1,"Description":"Represents backing compute resource"},"providers":{"Type":136,"Flags":0,"Description":"The Cloud providers configuration"},"simulated":{"Type":2,"Flags":0,"Description":"Simulated environment."},"recipes":{"Type":145,"Flags":0,"Description":"Specifies Recipes linked to the Environment."},"extensions":{"Type":146,"Flags":0,"Description":"The environment extension."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[128,129,130,131,132,133,134]}},{"2":{"Name":"Providers","Properties":{"azure":{"Type":137,"Flags":0,"Description":"The Azure cloud provider definition"},"aws":{"Type":138,"Flags":0,"Description":"The AWS cloud provider definition"}}}},{"2":{"Name":"ProvidersAzure","Properties":{"scope":{"Type":4,"Flags":1,"Description":"Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'"}}}},{"2":{"Name":"ProvidersAws","Properties":{"scope":{"Type":4,"Flags":1,"Description":"Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'"}}}},{"7":{"Name":"RecipeProperties","Discriminator":"templateKind","BaseProperties":{"templatePath":{"Type":4,"Flags":1,"Description":"Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported."},"parameters":{"Type":0,"Flags":0,"Description":"Any object"}},"Elements":{"bicep":140,"terraform":142}}},{"2":{"Name":"BicepRecipeProperties","Properties":{"plainHttp":{"Type":2,"Flags":0,"Description":"Connect to the Bicep registry using HTTP (not-HTTPS). This should be used when the registry is known not to support HTTPS, for example in a locally-hosted registry. Defaults to false (use HTTPS/TLS)."},"templateKind":{"Type":141,"Flags":1,"Description":"Discriminator property for RecipeProperties."}}}},{"6":{"Value":"bicep"}},{"2":{"Name":"TerraformRecipeProperties","Properties":{"templateVersion":{"Type":4,"Flags":0,"Description":"Version of the template to deploy. For Terraform recipes using a module registry this is required, but must be omitted for other module sources."},"templateKind":{"Type":143,"Flags":1,"Description":"Discriminator property for RecipeProperties."}}}},{"6":{"Value":"terraform"}},{"2":{"Name":"DictionaryOfRecipeProperties","Properties":{},"AdditionalProperties":139}},{"2":{"Name":"EnvironmentPropertiesRecipes","Properties":{},"AdditionalProperties":144}},{"3":{"ItemType":20}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/environments@2023-10-01-preview","ScopeType":0,"Body":126}},{"6":{"Value":"Applications.Core/extenders"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/extenders","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":149,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":150,"Flags":10,"Description":"The resource api version"},"properties":{"Type":152,"Flags":1,"Description":"ExtenderResource portable resource properties"},"tags":{"Type":165,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"ExtenderProperties","Properties":{"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the portable resource is linked to"},"application":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by (if applicable)"},"provisioningState":{"Type":160,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":0,"Flags":0,"Description":"Any object"},"recipe":{"Type":161,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":164,"Flags":0,"Description":"Specifies how the underlying service/resource is provisioned and managed. Available values are 'recipe', where Radius manages the lifecycle of the resource through a Recipe, and 'manual', where a user manages the resource and provides the values."}},"AdditionalProperties":0}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[153,154,155,156,157,158,159]}},{"2":{"Name":"Recipe","Properties":{"name":{"Type":4,"Flags":1,"Description":"The name of the recipe within the environment to use"},"parameters":{"Type":0,"Flags":0,"Description":"Any object"}}}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[162,163]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/extenders@2023-10-01-preview","ScopeType":0,"Body":151}},{"6":{"Value":"Applications.Core/gateways"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/gateways","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":167,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":168,"Flags":10,"Description":"The resource api version"},"properties":{"Type":170,"Flags":1,"Description":"Gateway properties"},"tags":{"Type":186,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"GatewayProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":178,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"internal":{"Type":2,"Flags":0,"Description":"Sets Gateway to not be exposed externally (no public IP address associated). Defaults to false (exposed to internet)."},"hostname":{"Type":179,"Flags":0,"Description":"Declare hostname information for the Gateway. Leaving the hostname empty auto-assigns one: mygateway.myapp.PUBLICHOSTNAMEORIP.nip.io."},"routes":{"Type":181,"Flags":1,"Description":"Routes attached to this Gateway"},"tls":{"Type":182,"Flags":0,"Description":"TLS configuration definition for Gateway resource."},"url":{"Type":4,"Flags":2,"Description":"URL of the gateway resource. Readonly"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[171,172,173,174,175,176,177]}},{"2":{"Name":"GatewayHostname","Properties":{"prefix":{"Type":4,"Flags":0,"Description":"Specify a prefix for the hostname: myhostname.myapp.PUBLICHOSTNAMEORIP.nip.io. Mutually exclusive with 'fullyQualifiedHostname' and will be overridden if both are defined."},"fullyQualifiedHostname":{"Type":4,"Flags":0,"Description":"Specify a fully-qualified domain name: myapp.mydomain.com. Mutually exclusive with 'prefix' and will take priority if both are defined."}}}},{"2":{"Name":"GatewayRoute","Properties":{"path":{"Type":4,"Flags":0,"Description":"The path to match the incoming request path on. Ex - /myservice."},"destination":{"Type":4,"Flags":0,"Description":"The HttpRoute to route to. Ex - myserviceroute.id."},"replacePrefix":{"Type":4,"Flags":0,"Description":"Optionally update the prefix when sending the request to the service. Ex - replacePrefix: '/' and path: '/myservice' will transform '/myservice/myroute' to '/myroute'"}}}},{"3":{"ItemType":180}},{"2":{"Name":"GatewayTls","Properties":{"sslPassthrough":{"Type":2,"Flags":0,"Description":"If true, gateway lets the https traffic sslPassthrough to the backend servers for decryption."},"minimumProtocolVersion":{"Type":185,"Flags":0,"Description":"Tls Minimum versions for Gateway resource."},"certificateFrom":{"Type":4,"Flags":0,"Description":"The resource id for the secret containing the TLS certificate and key for the gateway."}}}},{"6":{"Value":"1.2"}},{"6":{"Value":"1.3"}},{"5":{"Elements":[183,184]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/gateways@2023-10-01-preview","ScopeType":0,"Body":169}},{"6":{"Value":"Applications.Core/httpRoutes"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/httpRoutes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":188,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":189,"Flags":10,"Description":"The resource api version"},"properties":{"Type":191,"Flags":1,"Description":"HTTPRoute properties"},"tags":{"Type":200,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"HttpRouteProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":199,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"hostname":{"Type":4,"Flags":0,"Description":"The internal hostname accepting traffic for the HTTP Route. Readonly."},"port":{"Type":3,"Flags":0,"Description":"The port number for the HTTP Route. Defaults to 80. Readonly."},"scheme":{"Type":4,"Flags":2,"Description":"The scheme used for traffic. Readonly."},"url":{"Type":4,"Flags":2,"Description":"A stable URL that that can be used to route traffic to a resource. Readonly."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[192,193,194,195,196,197,198]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/httpRoutes@2023-10-01-preview","ScopeType":0,"Body":190}},{"6":{"Value":"Applications.Core/secretStores"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/secretStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":202,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":203,"Flags":10,"Description":"The resource api version"},"properties":{"Type":205,"Flags":1,"Description":"The properties of SecretStore"},"tags":{"Type":223,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"SecretStoreProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":213,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"type":{"Type":216,"Flags":0,"Description":"The type of SecretStore data"},"data":{"Type":222,"Flags":1,"Description":"An object to represent key-value type secrets"},"resource":{"Type":4,"Flags":0,"Description":"The resource id of external secret store."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[206,207,208,209,210,211,212]}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[214,215]}},{"2":{"Name":"SecretValueProperties","Properties":{"encoding":{"Type":220,"Flags":0,"Description":"The type of SecretValue Encoding"},"value":{"Type":4,"Flags":0,"Description":"The value of secret."},"valueFrom":{"Type":221,"Flags":0,"Description":"The Secret value source properties"}}}},{"6":{"Value":"raw"}},{"6":{"Value":"base64"}},{"5":{"Elements":[218,219]}},{"2":{"Name":"ValueFromProperties","Properties":{"name":{"Type":4,"Flags":1,"Description":"The name of the referenced secret."},"version":{"Type":4,"Flags":0,"Description":"The version of the referenced secret."}}}},{"2":{"Name":"SecretStorePropertiesData","Properties":{},"AdditionalProperties":217}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/secretStores@2023-10-01-preview","ScopeType":0,"Body":204}},{"6":{"Value":"Applications.Core/volumes"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/volumes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":225,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":226,"Flags":10,"Description":"The resource api version"},"properties":{"Type":228,"Flags":1,"Description":"Volume properties"},"tags":{"Type":260,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"7":{"Name":"VolumeProperties","Discriminator":"kind","BaseProperties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":236,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."}},"Elements":{"azure.com.keyvault":237}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[229,230,231,232,233,234,235]}},{"2":{"Name":"AzureKeyVaultVolumeProperties","Properties":{"certificates":{"Type":250,"Flags":0,"Description":"The KeyVault certificates that this volume exposes"},"keys":{"Type":252,"Flags":0,"Description":"The KeyVault keys that this volume exposes"},"resource":{"Type":4,"Flags":1,"Description":"The ID of the keyvault to use for this volume resource"},"secrets":{"Type":258,"Flags":0,"Description":"The KeyVault secrets that this volume exposes"},"kind":{"Type":259,"Flags":1,"Description":"Discriminator property for VolumeProperties."}}}},{"2":{"Name":"CertificateObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":242,"Flags":0,"Description":"Represents secret encodings"},"format":{"Type":245,"Flags":0,"Description":"Represents certificate formats"},"name":{"Type":4,"Flags":1,"Description":"The name of the certificate"},"certType":{"Type":249,"Flags":0,"Description":"Represents certificate types"},"version":{"Type":4,"Flags":0,"Description":"Certificate version"}}}},{"6":{"Value":"utf-8"}},{"6":{"Value":"hex"}},{"6":{"Value":"base64"}},{"5":{"Elements":[239,240,241]}},{"6":{"Value":"pem"}},{"6":{"Value":"pfx"}},{"5":{"Elements":[243,244]}},{"6":{"Value":"certificate"}},{"6":{"Value":"privatekey"}},{"6":{"Value":"publickey"}},{"5":{"Elements":[246,247,248]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesCertificates","Properties":{},"AdditionalProperties":238}},{"2":{"Name":"KeyObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"name":{"Type":4,"Flags":1,"Description":"The name of the key"},"version":{"Type":4,"Flags":0,"Description":"Key version"}}}},{"2":{"Name":"AzureKeyVaultVolumePropertiesKeys","Properties":{},"AdditionalProperties":251}},{"2":{"Name":"SecretObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":257,"Flags":0,"Description":"Represents secret encodings"},"name":{"Type":4,"Flags":1,"Description":"The name of the secret"},"version":{"Type":4,"Flags":0,"Description":"secret version"}}}},{"6":{"Value":"utf-8"}},{"6":{"Value":"hex"}},{"6":{"Value":"base64"}},{"5":{"Elements":[254,255,256]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesSecrets","Properties":{},"AdditionalProperties":253}},{"6":{"Value":"azure.com.keyvault"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/volumes@2023-10-01-preview","ScopeType":0,"Body":227}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/extenders","ApiVersion":"2023-10-01-preview","Output":0,"Input":0}},{"2":{"Name":"SecretStoreListSecretsResult","Properties":{"type":{"Type":266,"Flags":2,"Description":"The type of SecretStore data"},"data":{"Type":267,"Flags":2,"Description":"An object to represent key-value type secrets"}}}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[264,265]}},{"2":{"Name":"SecretStoreListSecretsResultData","Properties":{},"AdditionalProperties":217}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/secretStores","ApiVersion":"2023-10-01-preview","Output":263,"Input":0}}] \ No newline at end of file +[{"1":{"Kind":1}},{"1":{"Kind":2}},{"1":{"Kind":3}},{"1":{"Kind":4}},{"1":{"Kind":5}},{"1":{"Kind":6}},{"1":{"Kind":7}},{"1":{"Kind":8}},{"6":{"Value":"Applications.Core/applications"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/applications","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":8,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":9,"Flags":10,"Description":"The resource api version"},"properties":{"Type":11,"Flags":1,"Description":"Application properties"},"tags":{"Type":46,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"ApplicationProperties","Properties":{"provisioningState":{"Type":19,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"extensions":{"Type":34,"Flags":0,"Description":"The application extension."},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[12,13,14,15,16,17,18]}},{"7":{"Name":"Extension","Discriminator":"kind","BaseProperties":{},"Elements":{"daprSidecar":21,"kubernetesMetadata":26,"kubernetesNamespace":30,"manualScaling":32}}},{"2":{"Name":"DaprSidecarExtension","Properties":{"appPort":{"Type":3,"Flags":0,"Description":"The Dapr appPort. Specifies the internal listening port for the application to handle requests from the Dapr sidecar."},"appId":{"Type":4,"Flags":1,"Description":"The Dapr appId. Specifies the identifier used by Dapr for service invocation."},"config":{"Type":4,"Flags":0,"Description":"Specifies the Dapr configuration to use for the resource."},"protocol":{"Type":24,"Flags":0,"Description":"The Dapr sidecar extension protocol"},"kind":{"Type":25,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"6":{"Value":"http"}},{"6":{"Value":"grpc"}},{"5":{"Elements":[22,23]}},{"6":{"Value":"daprSidecar"}},{"2":{"Name":"KubernetesMetadataExtension","Properties":{"annotations":{"Type":27,"Flags":0,"Description":"Annotations to be applied to the Kubernetes resources output by the resource"},"labels":{"Type":28,"Flags":0,"Description":"Labels to be applied to the Kubernetes resources output by the resource"},"kind":{"Type":29,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"2":{"Name":"KubernetesMetadataExtensionAnnotations","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"KubernetesMetadataExtensionLabels","Properties":{},"AdditionalProperties":4}},{"6":{"Value":"kubernetesMetadata"}},{"2":{"Name":"KubernetesNamespaceExtension","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace of the application environment."},"kind":{"Type":31,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"6":{"Value":"kubernetesNamespace"}},{"2":{"Name":"ManualScalingExtension","Properties":{"replicas":{"Type":3,"Flags":1,"Description":"Replica count."},"kind":{"Type":33,"Flags":1,"Description":"Discriminator property for Extension."}}}},{"6":{"Value":"manualScaling"}},{"3":{"ItemType":20}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":36,"Flags":0,"Description":"Represents backing compute resource"},"recipe":{"Type":43,"Flags":2,"Description":"Recipe status at deployment time for a resource."},"outputResources":{"Type":45,"Flags":0,"Description":"Properties of an output resource"}}}},{"7":{"Name":"EnvironmentCompute","Discriminator":"kind","BaseProperties":{"resourceId":{"Type":4,"Flags":0,"Description":"The resource id of the compute resource for application environment."},"identity":{"Type":37,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":41}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":40,"Flags":1,"Description":"IdentitySettingKind is the kind of supported external identity setting"},"oidcIssuer":{"Type":4,"Flags":0,"Description":"The URI for your compute platform's OIDC issuer"},"resource":{"Type":4,"Flags":0,"Description":"The resource ID of the provisioned identity"}}}},{"6":{"Value":"undefined"}},{"6":{"Value":"azure.com.workload"}},{"5":{"Elements":[38,39]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":42,"Flags":1,"Description":"Discriminator property for EnvironmentCompute."}}}},{"6":{"Value":"kubernetes"}},{"2":{"Name":"RecipeStatus","Properties":{"templateKind":{"Type":4,"Flags":1,"Description":"TemplateKind is the kind of the recipe template used by the portable resource upon deployment."},"templatePath":{"Type":4,"Flags":1,"Description":"TemplatePath is the path of the recipe consumed by the portable resource upon deployment."},"templateVersion":{"Type":4,"Flags":0,"Description":"TemplateVersion is the version number of the template."}}}},{"2":{"Name":"OutputResource","Properties":{"localId":{"Type":4,"Flags":0,"Description":"The logical identifier scoped to the owning Radius resource. This is only needed or used when a resource has a dependency relationship. LocalIDs do not have any particular format or meaning beyond being compared to determine dependency relationships."},"id":{"Type":4,"Flags":0,"Description":"The UCP resource ID of the underlying resource."},"radiusManaged":{"Type":2,"Flags":0,"Description":"Determines whether Radius manages the lifecycle of the underlying resource."}}}},{"3":{"ItemType":44}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":52,"Flags":0,"Description":"The type of identity that created the resource."},"createdAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource creation (UTC)."},"lastModifiedBy":{"Type":4,"Flags":0,"Description":"The identity that last modified the resource."},"lastModifiedByType":{"Type":57,"Flags":0,"Description":"The type of identity that created the resource."},"lastModifiedAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource last modification (UTC)"}}}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[48,49,50,51]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[53,54,55,56]}},{"4":{"Name":"Applications.Core/applications@2023-10-01-preview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Core/containers"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/containers","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":59,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":60,"Flags":10,"Description":"The resource api version"},"properties":{"Type":62,"Flags":1,"Description":"Container properties"},"tags":{"Type":122,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"ContainerProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":70,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"container":{"Type":71,"Flags":1,"Description":"Definition of a container"},"connections":{"Type":108,"Flags":0,"Description":"Specifies a connection to another resource."},"identity":{"Type":37,"Flags":0,"Description":"IdentitySettings is the external identity setting."},"extensions":{"Type":109,"Flags":0,"Description":"Extensions spec of the resource"},"resourceProvisioning":{"Type":112,"Flags":0,"Description":"Specifies how the underlying service/resource is provisioned and managed. Available values are 'internal', where Radius manages the lifecycle of the resource internally, and 'manual', where a user manages the resource."},"resources":{"Type":114,"Flags":0,"Description":"A collection of references to resources associated with the container"},"restartPolicy":{"Type":118,"Flags":0,"Description":"Restart policy for the container"},"runtimes":{"Type":119,"Flags":0,"Description":"The properties for runtime configuration"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[63,64,65,66,67,68,69]}},{"2":{"Name":"Container","Properties":{"image":{"Type":4,"Flags":1,"Description":"The registry and image to download and run in your container"},"imagePullPolicy":{"Type":75,"Flags":0,"Description":"The image pull policy for the container"},"env":{"Type":76,"Flags":0,"Description":"environment"},"ports":{"Type":81,"Flags":0,"Description":"container ports"},"readinessProbe":{"Type":82,"Flags":0,"Description":"Properties for readiness/liveness probe"},"livenessProbe":{"Type":82,"Flags":0,"Description":"Properties for readiness/liveness probe"},"volumes":{"Type":101,"Flags":0,"Description":"container volumes"},"command":{"Type":102,"Flags":0,"Description":"Entrypoint array. Overrides the container image's ENTRYPOINT"},"args":{"Type":103,"Flags":0,"Description":"Arguments to the entrypoint. Overrides the container image's CMD"},"workingDir":{"Type":4,"Flags":0,"Description":"Working directory for the container"}}}},{"6":{"Value":"Always"}},{"6":{"Value":"IfNotPresent"}},{"6":{"Value":"Never"}},{"5":{"Elements":[72,73,74]}},{"2":{"Name":"ContainerEnv","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"ContainerPortProperties","Properties":{"containerPort":{"Type":3,"Flags":1,"Description":"The listening port number"},"protocol":{"Type":80,"Flags":0,"Description":"The protocol in use by the port"},"provides":{"Type":4,"Flags":0,"Description":"Specifies a route provided by this port"},"scheme":{"Type":4,"Flags":0,"Description":"Specifies the URL scheme of the communication protocol. Consumers can use the scheme to construct a URL. The value defaults to 'http' or 'https' depending on the port value"},"port":{"Type":3,"Flags":0,"Description":"Specifies the port that will be exposed by this container. Must be set when value different from containerPort is desired"}}}},{"6":{"Value":"TCP"}},{"6":{"Value":"UDP"}},{"5":{"Elements":[78,79]}},{"2":{"Name":"ContainerPorts","Properties":{},"AdditionalProperties":77}},{"7":{"Name":"HealthProbeProperties","Discriminator":"kind","BaseProperties":{"initialDelaySeconds":{"Type":3,"Flags":0,"Description":"Initial delay in seconds before probing for readiness/liveness"},"failureThreshold":{"Type":3,"Flags":0,"Description":"Threshold number of times the probe fails after which a failure would be reported"},"periodSeconds":{"Type":3,"Flags":0,"Description":"Interval for the readiness/liveness probe in seconds"},"timeoutSeconds":{"Type":3,"Flags":0,"Description":"Number of seconds after which the readiness/liveness probe times out. Defaults to 5 seconds"}},"Elements":{"exec":83,"httpGet":85,"tcp":88}}},{"2":{"Name":"ExecHealthProbeProperties","Properties":{"command":{"Type":4,"Flags":1,"Description":"Command to execute to probe readiness/liveness"},"kind":{"Type":84,"Flags":1,"Description":"Discriminator property for HealthProbeProperties."}}}},{"6":{"Value":"exec"}},{"2":{"Name":"HttpGetHealthProbeProperties","Properties":{"containerPort":{"Type":3,"Flags":1,"Description":"The listening port number"},"path":{"Type":4,"Flags":1,"Description":"The route to make the HTTP request on"},"headers":{"Type":86,"Flags":0,"Description":"Custom HTTP headers to add to the get request"},"kind":{"Type":87,"Flags":1,"Description":"Discriminator property for HealthProbeProperties."}}}},{"2":{"Name":"HttpGetHealthProbePropertiesHeaders","Properties":{},"AdditionalProperties":4}},{"6":{"Value":"httpGet"}},{"2":{"Name":"TcpHealthProbeProperties","Properties":{"containerPort":{"Type":3,"Flags":1,"Description":"The listening port number"},"kind":{"Type":89,"Flags":1,"Description":"Discriminator property for HealthProbeProperties."}}}},{"6":{"Value":"tcp"}},{"7":{"Name":"Volume","Discriminator":"kind","BaseProperties":{"mountPath":{"Type":4,"Flags":0,"Description":"The path where the volume is mounted"}},"Elements":{"ephemeral":91,"persistent":96}}},{"2":{"Name":"EphemeralVolume","Properties":{"managedStore":{"Type":94,"Flags":1,"Description":"The managed store for the ephemeral volume"},"kind":{"Type":95,"Flags":1,"Description":"Discriminator property for Volume."}}}},{"6":{"Value":"memory"}},{"6":{"Value":"disk"}},{"5":{"Elements":[92,93]}},{"6":{"Value":"ephemeral"}},{"2":{"Name":"PersistentVolume","Properties":{"permission":{"Type":99,"Flags":0,"Description":"The persistent volume permission"},"source":{"Type":4,"Flags":1,"Description":"The source of the volume"},"kind":{"Type":100,"Flags":1,"Description":"Discriminator property for Volume."}}}},{"6":{"Value":"read"}},{"6":{"Value":"write"}},{"5":{"Elements":[97,98]}},{"6":{"Value":"persistent"}},{"2":{"Name":"ContainerVolumes","Properties":{},"AdditionalProperties":90}},{"3":{"ItemType":4}},{"3":{"ItemType":4}},{"2":{"Name":"ConnectionProperties","Properties":{"source":{"Type":4,"Flags":1,"Description":"The source of the connection"},"disableDefaultEnvVars":{"Type":2,"Flags":0,"Description":"default environment variable override"},"iam":{"Type":105,"Flags":0,"Description":"IAM properties"}}}},{"2":{"Name":"IamProperties","Properties":{"kind":{"Type":106,"Flags":1,"Description":"The kind of IAM provider to configure"},"roles":{"Type":107,"Flags":0,"Description":"RBAC permissions to be assigned on the source resource"}}}},{"6":{"Value":"azure"}},{"3":{"ItemType":4}},{"2":{"Name":"ContainerPropertiesConnections","Properties":{},"AdditionalProperties":104}},{"3":{"ItemType":20}},{"6":{"Value":"internal"}},{"6":{"Value":"manual"}},{"5":{"Elements":[110,111]}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":113}},{"6":{"Value":"Always"}},{"6":{"Value":"OnFailure"}},{"6":{"Value":"Never"}},{"5":{"Elements":[115,116,117]}},{"2":{"Name":"RuntimesProperties","Properties":{"kubernetes":{"Type":120,"Flags":0,"Description":"The runtime configuration properties for Kubernetes"}}}},{"2":{"Name":"KubernetesRuntimeProperties","Properties":{"base":{"Type":4,"Flags":0,"Description":"The serialized YAML manifest which represents the base Kubernetes resources to deploy, such as Deployment, Service, ServiceAccount, Secrets, and ConfigMaps."},"pod":{"Type":121,"Flags":0,"Description":"A strategic merge patch that will be applied to the PodSpec object when this container is being deployed."}}}},{"2":{"Name":"KubernetesPodSpec","Properties":{},"AdditionalProperties":0}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/containers@2023-10-01-preview","ScopeType":0,"Body":61}},{"6":{"Value":"Applications.Core/environments"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/environments","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":124,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":125,"Flags":10,"Description":"The resource api version"},"properties":{"Type":127,"Flags":1,"Description":"Environment properties"},"tags":{"Type":147,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"EnvironmentProperties","Properties":{"provisioningState":{"Type":135,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"compute":{"Type":36,"Flags":1,"Description":"Represents backing compute resource"},"providers":{"Type":136,"Flags":0,"Description":"The Cloud providers configuration"},"simulated":{"Type":2,"Flags":0,"Description":"Simulated environment."},"recipes":{"Type":145,"Flags":0,"Description":"Specifies Recipes linked to the Environment."},"extensions":{"Type":146,"Flags":0,"Description":"The environment extension."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[128,129,130,131,132,133,134]}},{"2":{"Name":"Providers","Properties":{"azure":{"Type":137,"Flags":0,"Description":"The Azure cloud provider definition"},"aws":{"Type":138,"Flags":0,"Description":"The AWS cloud provider definition"}}}},{"2":{"Name":"ProvidersAzure","Properties":{"scope":{"Type":4,"Flags":1,"Description":"Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'"}}}},{"2":{"Name":"ProvidersAws","Properties":{"scope":{"Type":4,"Flags":1,"Description":"Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'"}}}},{"7":{"Name":"RecipeProperties","Discriminator":"templateKind","BaseProperties":{"templatePath":{"Type":4,"Flags":1,"Description":"Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported."},"parameters":{"Type":0,"Flags":0,"Description":"Any object"}},"Elements":{"bicep":140,"terraform":142}}},{"2":{"Name":"BicepRecipeProperties","Properties":{"plainHttp":{"Type":2,"Flags":0,"Description":"Connect to the Bicep registry using HTTP (not-HTTPS). This should be used when the registry is known not to support HTTPS, for example in a locally-hosted registry. Defaults to false (use HTTPS/TLS)."},"templateKind":{"Type":141,"Flags":1,"Description":"Discriminator property for RecipeProperties."}}}},{"6":{"Value":"bicep"}},{"2":{"Name":"TerraformRecipeProperties","Properties":{"templateVersion":{"Type":4,"Flags":0,"Description":"Version of the template to deploy. For Terraform recipes using a module registry this is required, but must be omitted for other module sources."},"templateKind":{"Type":143,"Flags":1,"Description":"Discriminator property for RecipeProperties."}}}},{"6":{"Value":"terraform"}},{"2":{"Name":"DictionaryOfRecipeProperties","Properties":{},"AdditionalProperties":139}},{"2":{"Name":"EnvironmentPropertiesRecipes","Properties":{},"AdditionalProperties":144}},{"3":{"ItemType":20}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/environments@2023-10-01-preview","ScopeType":0,"Body":126}},{"6":{"Value":"Applications.Core/extenders"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/extenders","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":149,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":150,"Flags":10,"Description":"The resource api version"},"properties":{"Type":152,"Flags":1,"Description":"ExtenderResource portable resource properties"},"tags":{"Type":165,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"ExtenderProperties","Properties":{"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the portable resource is linked to"},"application":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by (if applicable)"},"provisioningState":{"Type":160,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":0,"Flags":0,"Description":"Any object"},"recipe":{"Type":161,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":164,"Flags":0,"Description":"Specifies how the underlying service/resource is provisioned and managed. Available values are 'recipe', where Radius manages the lifecycle of the resource through a Recipe, and 'manual', where a user manages the resource and provides the values."}},"AdditionalProperties":0}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[153,154,155,156,157,158,159]}},{"2":{"Name":"Recipe","Properties":{"name":{"Type":4,"Flags":1,"Description":"The name of the recipe within the environment to use"},"parameters":{"Type":0,"Flags":0,"Description":"Any object"}}}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[162,163]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/extenders@2023-10-01-preview","ScopeType":0,"Body":151}},{"6":{"Value":"Applications.Core/gateways"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/gateways","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":167,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":168,"Flags":10,"Description":"The resource api version"},"properties":{"Type":170,"Flags":1,"Description":"Gateway properties"},"tags":{"Type":186,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"GatewayProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":178,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"internal":{"Type":2,"Flags":0,"Description":"Sets Gateway to not be exposed externally (no public IP address associated). Defaults to false (exposed to internet)."},"hostname":{"Type":179,"Flags":0,"Description":"Declare hostname information for the Gateway. Leaving the hostname empty auto-assigns one: mygateway.myapp.PUBLICHOSTNAMEORIP.nip.io."},"routes":{"Type":181,"Flags":1,"Description":"Routes attached to this Gateway"},"tls":{"Type":182,"Flags":0,"Description":"TLS configuration definition for Gateway resource."},"url":{"Type":4,"Flags":2,"Description":"URL of the gateway resource. Readonly"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[171,172,173,174,175,176,177]}},{"2":{"Name":"GatewayHostname","Properties":{"prefix":{"Type":4,"Flags":0,"Description":"Specify a prefix for the hostname: myhostname.myapp.PUBLICHOSTNAMEORIP.nip.io. Mutually exclusive with 'fullyQualifiedHostname' and will be overridden if both are defined."},"fullyQualifiedHostname":{"Type":4,"Flags":0,"Description":"Specify a fully-qualified domain name: myapp.mydomain.com. Mutually exclusive with 'prefix' and will take priority if both are defined."}}}},{"2":{"Name":"GatewayRoute","Properties":{"path":{"Type":4,"Flags":0,"Description":"The path to match the incoming request path on. Ex - /myservice."},"destination":{"Type":4,"Flags":0,"Description":"The HttpRoute to route to. Ex - myserviceroute.id."},"replacePrefix":{"Type":4,"Flags":0,"Description":"Optionally update the prefix when sending the request to the service. Ex - replacePrefix: '/' and path: '/myservice' will transform '/myservice/myroute' to '/myroute'"}}}},{"3":{"ItemType":180}},{"2":{"Name":"GatewayTls","Properties":{"sslPassthrough":{"Type":2,"Flags":0,"Description":"If true, gateway lets the https traffic sslPassthrough to the backend servers for decryption."},"minimumProtocolVersion":{"Type":185,"Flags":0,"Description":"Tls Minimum versions for Gateway resource."},"certificateFrom":{"Type":4,"Flags":0,"Description":"The resource id for the secret containing the TLS certificate and key for the gateway."}}}},{"6":{"Value":"1.2"}},{"6":{"Value":"1.3"}},{"5":{"Elements":[183,184]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/gateways@2023-10-01-preview","ScopeType":0,"Body":169}},{"6":{"Value":"Applications.Core/httpRoutes"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/httpRoutes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":188,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":189,"Flags":10,"Description":"The resource api version"},"properties":{"Type":191,"Flags":1,"Description":"HTTPRoute properties"},"tags":{"Type":200,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"HttpRouteProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":199,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"hostname":{"Type":4,"Flags":0,"Description":"The internal hostname accepting traffic for the HTTP Route. Readonly."},"port":{"Type":3,"Flags":0,"Description":"The port number for the HTTP Route. Defaults to 80. Readonly."},"scheme":{"Type":4,"Flags":2,"Description":"The scheme used for traffic. Readonly."},"url":{"Type":4,"Flags":2,"Description":"A stable URL that that can be used to route traffic to a resource. Readonly."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[192,193,194,195,196,197,198]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/httpRoutes@2023-10-01-preview","ScopeType":0,"Body":190}},{"6":{"Value":"Applications.Core/secretStores"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/secretStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":202,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":203,"Flags":10,"Description":"The resource api version"},"properties":{"Type":205,"Flags":1,"Description":"The properties of SecretStore"},"tags":{"Type":223,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"SecretStoreProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":213,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"type":{"Type":216,"Flags":0,"Description":"The type of SecretStore data"},"data":{"Type":222,"Flags":1,"Description":"An object to represent key-value type secrets"},"resource":{"Type":4,"Flags":0,"Description":"The resource id of external secret store."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[206,207,208,209,210,211,212]}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[214,215]}},{"2":{"Name":"SecretValueProperties","Properties":{"encoding":{"Type":220,"Flags":0,"Description":"The type of SecretValue Encoding"},"value":{"Type":4,"Flags":0,"Description":"The value of secret."},"valueFrom":{"Type":221,"Flags":0,"Description":"The Secret value source properties"}}}},{"6":{"Value":"raw"}},{"6":{"Value":"base64"}},{"5":{"Elements":[218,219]}},{"2":{"Name":"ValueFromProperties","Properties":{"name":{"Type":4,"Flags":1,"Description":"The name of the referenced secret."},"version":{"Type":4,"Flags":0,"Description":"The version of the referenced secret."}}}},{"2":{"Name":"SecretStorePropertiesData","Properties":{},"AdditionalProperties":217}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/secretStores@2023-10-01-preview","ScopeType":0,"Body":204}},{"6":{"Value":"Applications.Core/volumes"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/volumes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":225,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":226,"Flags":10,"Description":"The resource api version"},"properties":{"Type":228,"Flags":1,"Description":"Volume properties"},"tags":{"Type":260,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"7":{"Name":"VolumeProperties","Discriminator":"kind","BaseProperties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the application is linked to"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application"},"provisioningState":{"Type":236,"Flags":2,"Description":"Provisioning state of the resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."}},"Elements":{"azure.com.keyvault":237}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[229,230,231,232,233,234,235]}},{"2":{"Name":"AzureKeyVaultVolumeProperties","Properties":{"certificates":{"Type":250,"Flags":0,"Description":"The KeyVault certificates that this volume exposes"},"keys":{"Type":252,"Flags":0,"Description":"The KeyVault keys that this volume exposes"},"resource":{"Type":4,"Flags":1,"Description":"The ID of the keyvault to use for this volume resource"},"secrets":{"Type":258,"Flags":0,"Description":"The KeyVault secrets that this volume exposes"},"kind":{"Type":259,"Flags":1,"Description":"Discriminator property for VolumeProperties."}}}},{"2":{"Name":"CertificateObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":242,"Flags":0,"Description":"Represents secret encodings"},"format":{"Type":245,"Flags":0,"Description":"Represents certificate formats"},"name":{"Type":4,"Flags":1,"Description":"The name of the certificate"},"certType":{"Type":249,"Flags":0,"Description":"Represents certificate types"},"version":{"Type":4,"Flags":0,"Description":"Certificate version"}}}},{"6":{"Value":"utf-8"}},{"6":{"Value":"hex"}},{"6":{"Value":"base64"}},{"5":{"Elements":[239,240,241]}},{"6":{"Value":"pem"}},{"6":{"Value":"pfx"}},{"5":{"Elements":[243,244]}},{"6":{"Value":"certificate"}},{"6":{"Value":"privatekey"}},{"6":{"Value":"publickey"}},{"5":{"Elements":[246,247,248]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesCertificates","Properties":{},"AdditionalProperties":238}},{"2":{"Name":"KeyObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"name":{"Type":4,"Flags":1,"Description":"The name of the key"},"version":{"Type":4,"Flags":0,"Description":"Key version"}}}},{"2":{"Name":"AzureKeyVaultVolumePropertiesKeys","Properties":{},"AdditionalProperties":251}},{"2":{"Name":"SecretObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":257,"Flags":0,"Description":"Represents secret encodings"},"name":{"Type":4,"Flags":1,"Description":"The name of the secret"},"version":{"Type":4,"Flags":0,"Description":"secret version"}}}},{"6":{"Value":"utf-8"}},{"6":{"Value":"hex"}},{"6":{"Value":"base64"}},{"5":{"Elements":[254,255,256]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesSecrets","Properties":{},"AdditionalProperties":253}},{"6":{"Value":"azure.com.keyvault"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/volumes@2023-10-01-preview","ScopeType":0,"Body":227}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/extenders","ApiVersion":"2023-10-01-preview","Output":0,"Input":0}},{"2":{"Name":"SecretStoreListSecretsResult","Properties":{"type":{"Type":266,"Flags":2,"Description":"The type of SecretStore data"},"data":{"Type":267,"Flags":2,"Description":"An object to represent key-value type secrets"}}}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[264,265]}},{"2":{"Name":"SecretStoreListSecretsResultData","Properties":{},"AdditionalProperties":217}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/secretStores","ApiVersion":"2023-10-01-preview","Output":263,"Input":0}}] \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/zz_generated_models.go b/pkg/corerp/api/v20231001preview/zz_generated_models.go index 0170d202ac..72a5e0b8c5 100644 --- a/pkg/corerp/api/v20231001preview/zz_generated_models.go +++ b/pkg/corerp/api/v20231001preview/zz_generated_models.go @@ -1513,12 +1513,12 @@ type SecretStoreListSecretsResult struct { // SecretStoreProperties - The properties of SecretStore type SecretStoreProperties struct { - // REQUIRED; Fully qualified resource ID for the application - Application *string - // REQUIRED; An object to represent key-value type secrets Data map[string]*SecretValueProperties + // Fully qualified resource ID for the application + Application *string + // Fully qualified resource ID for the environment that the application is linked to Environment *string diff --git a/pkg/corerp/frontend/controller/secretstores/kubernetes.go b/pkg/corerp/frontend/controller/secretstores/kubernetes.go index f25562c2c7..3825a03a21 100644 --- a/pkg/corerp/frontend/controller/secretstores/kubernetes.go +++ b/pkg/corerp/frontend/controller/secretstores/kubernetes.go @@ -27,6 +27,7 @@ import ( "github.com/radius-project/radius/pkg/armrpc/rest" "github.com/radius-project/radius/pkg/corerp/datamodel" "github.com/radius-project/radius/pkg/kubernetes" + "github.com/radius-project/radius/pkg/kubeutil" rpv1 "github.com/radius-project/radius/pkg/rp/v1" "github.com/radius-project/radius/pkg/to" "github.com/radius-project/radius/pkg/ucp/resources" @@ -184,6 +185,11 @@ func UpsertSecret(ctx context.Context, newResource, old *datamodel.SecretStore, ref = old.Properties.Resource } + // resource property cannot be empty for global scoped resource. + if newResource.Properties.BasicResourceProperties.IsGlobalScopedResource() && ref == "" { + return rest.NewBadRequestResponse("$.properties.resource cannot be empty for global scoped resource."), nil + } + ns, name, err := fromResourceID(ref) if err != nil { return nil, err @@ -195,6 +201,12 @@ func UpsertSecret(ctx context.Context, newResource, old *datamodel.SecretStore, } } + // Create namespace if not exists. + err = kubeutil.PatchNamespace(ctx, options.KubeClient, ns) + if err != nil { + return nil, err + } + if name == "" { name = newResource.Name } @@ -208,8 +220,9 @@ func UpsertSecret(ctx context.Context, newResource, old *datamodel.SecretStore, ksecret := &corev1.Secret{} err = options.KubeClient.Get(ctx, runtimeclient.ObjectKey{Namespace: ns, Name: name}, ksecret) if apierrors.IsNotFound(err) { - // If resource in incoming request references resource, then the resource must exist. - if ref != "" { + // If resource in incoming request references resource, then the resource must exist for a application/environment scoped resource. + // For global scoped resource create the kubernetes resource if not exists. + if ref != "" && !newResource.Properties.BasicResourceProperties.IsGlobalScopedResource() { return rest.NewBadRequestResponse(fmt.Sprintf("'%s' referenced resource does not exist.", ref)), nil } app, _ := resources.ParseResource(newResource.Properties.Application) diff --git a/pkg/corerp/frontend/controller/secretstores/kubernetes_test.go b/pkg/corerp/frontend/controller/secretstores/kubernetes_test.go index 1b300409e1..69d61fa3cf 100644 --- a/pkg/corerp/frontend/controller/secretstores/kubernetes_test.go +++ b/pkg/corerp/frontend/controller/secretstores/kubernetes_test.go @@ -45,9 +45,12 @@ const ( testEnvID = testRootScope + "/Applications.Core/environments/env0" testAppID = testRootScope + "/Applications.Core/applications/app0" - testFileCertValueFrom = "secretstores_datamodel_cert_valuefrom.json" - testFileCertValue = "secretstores_datamodel_cert_value.json" - testFileGenericValue = "secretstores_datamodel_generic.json" + testFileCertValueFrom = "secretstores_datamodel_cert_valuefrom.json" + testFileCertValue = "secretstores_datamodel_cert_value.json" + testFileGenericValue = "secretstores_datamodel_generic.json" + testFileGenericValueGlobalScope = "secretstores_datamodel_global_scope.json" + testFileGenericValueInvalidResource = "secretstores_datamodel_global_scope_invalid_resource.json" + testFileGenericValueEmptyResource = "secretstores_datamodel_global_scope_empty_resource.json" ) func TestGetNamespace(t *testing.T) { @@ -466,6 +469,109 @@ func TestUpsertSecret(t *testing.T) { require.Equal(t, "'app0-ns/secret1' of $.properties.resource must be same as 'app0-ns/secret0'.", r.Body.Error.Message) }) + t.Run("create a new secret resource with global scope", func(t *testing.T) { + ctrl := gomock.NewController(t) + sc := store.NewMockStorageClient(ctrl) + + newResource := testutil.MustGetTestData[datamodel.SecretStore](testFileGenericValueGlobalScope) + + opt := &controller.Options{ + StorageClient: sc, + KubeClient: k8sutil.NewFakeKubeClient(nil), + } + + _, err := ValidateAndMutateRequest(context.TODO(), newResource, nil, opt) + require.NoError(t, err) + _, err = UpsertSecret(context.TODO(), newResource, nil, opt) + require.NoError(t, err) + + // assert + require.Equal(t, "test-namespace/secret0", newResource.Properties.Resource) + ksecret := &corev1.Secret{} + + err = opt.KubeClient.Get(context.TODO(), runtimeclient.ObjectKey{Namespace: "test-namespace", Name: "secret0"}, ksecret) + require.NoError(t, err) + + require.Equal(t, "dGxzLmNydA==", string(ksecret.Data["tls.crt"])) + require.Equal(t, "dGxzLmNlcnQK", string(ksecret.Data["tls.key"])) + require.Equal(t, "MTAwMDAwMDAtMTAwMC0xMDAwLTAwMDAtMDAwMDAwMDAwMDAw", string(ksecret.Data["servicePrincipalPassword"])) + require.Equal(t, rpv1.OutputResource{ + LocalID: "Secret", + ID: resources_kubernetes.IDFromParts( + resources_kubernetes.PlaneNameTODO, + "", + resources_kubernetes.KindSecret, + "test-namespace", + "secret0"), + }, newResource.Properties.Status.OutputResources[0]) + }) + + t.Run("create a new secret resource with invalid resource", func(t *testing.T) { + ctrl := gomock.NewController(t) + sc := store.NewMockStorageClient(ctrl) + + newResource := testutil.MustGetTestData[datamodel.SecretStore](testFileGenericValueInvalidResource) + + opt := &controller.Options{ + StorageClient: sc, + KubeClient: k8sutil.NewFakeKubeClient(nil), + } + + _, err := ValidateAndMutateRequest(context.TODO(), newResource, nil, opt) + require.NoError(t, err) + _, err = UpsertSecret(context.TODO(), newResource, nil, opt) + require.Error(t, err) + require.Equal(t, err.Error(), "no Kubernetes namespace") + }) + + t.Run("create a new secret resource with empty resource", func(t *testing.T) { + ctrl := gomock.NewController(t) + sc := store.NewMockStorageClient(ctrl) + + newResource := testutil.MustGetTestData[datamodel.SecretStore](testFileGenericValueEmptyResource) + + opt := &controller.Options{ + StorageClient: sc, + KubeClient: k8sutil.NewFakeKubeClient(nil), + } + + _, err := ValidateAndMutateRequest(context.TODO(), newResource, nil, opt) + require.NoError(t, err) + resp, err := UpsertSecret(context.TODO(), newResource, nil, opt) + require.NoError(t, err) + + // assert + r := resp.(*rest.BadRequestResponse) + require.Equal(t, "$.properties.resource cannot be empty for global scoped resource.", r.Body.Error.Message) + }) + + t.Run("add secret values to the existing secret store 1 ", func(t *testing.T) { + newResource := testutil.MustGetTestData[datamodel.SecretStore](testFileCertValue) + newResource.Properties.Resource = "default/secret" + + opt := &controller.Options{ + KubeClient: k8sutil.NewFakeKubeClient(nil), + } + + resp, _ := UpsertSecret(context.TODO(), newResource, nil, opt) + r := resp.(*rest.BadRequestResponse) + require.Equal(t, "'default/secret' referenced resource does not exist.", r.Body.Error.Message) + }) + + t.Run("inherit old resource id for global scoped resource", func(t *testing.T) { + oldResource := testutil.MustGetTestData[datamodel.SecretStore](testFileGenericValueGlobalScope) + newResource := testutil.MustGetTestData[datamodel.SecretStore](testFileGenericValueEmptyResource) + + opt := &controller.Options{ + KubeClient: k8sutil.NewFakeKubeClient(nil), + } + + _, err := UpsertSecret(context.TODO(), newResource, oldResource, opt) + require.NoError(t, err) + + // assert + require.Equal(t, oldResource.Properties.Resource, newResource.Properties.Resource) + }) } func TestDeleteSecret(t *testing.T) { diff --git a/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope.json b/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope.json new file mode 100644 index 0000000000..653916fa62 --- /dev/null +++ b/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope.json @@ -0,0 +1,37 @@ +{ + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/secretStores/secret0", + "name": "secret0", + "type": "applications.core/secretstores", + "location": "global", + "systemData": { + "createdAt": "2022-03-22T18:54:52.6857175Z", + "createdBy": "fake@hotmail.com", + "createdByType": "User", + "lastModifiedAt": "2022-03-22T18:57:52.6857175Z", + "lastModifiedBy": "fake@hotmail.com", + "lastModifiedByType": "User" + }, + "provisioningState": "Succeeded", + "properties": { + "resource": "test-namespace/secret0", + "type": "generic", + "data": { + "tls.crt": { + "encoding": "raw", + "value": "tls.crt" + }, + "tls.key": { + "encoding": "base64", + "value": "dGxzLmNlcnQK" + }, + "servicePrincipalPassword": { + "value": "10000000-1000-1000-0000-000000000000" + } + } + }, + "tenantId": "00000000-0000-0000-0000-000000000000", + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "resourceGroup": "testGroup", + "createdApiVersion": "2023-10-01-preview", + "updatedApiVersion": "2023-10-01-preview" + } \ No newline at end of file diff --git a/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_empty_resource.json b/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_empty_resource.json new file mode 100644 index 0000000000..8cacca13bd --- /dev/null +++ b/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_empty_resource.json @@ -0,0 +1,36 @@ +{ + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/secretStores/secret0", + "name": "secret0", + "type": "applications.core/secretstores", + "location": "global", + "systemData": { + "createdAt": "2022-03-22T18:54:52.6857175Z", + "createdBy": "fake@hotmail.com", + "createdByType": "User", + "lastModifiedAt": "2022-03-22T18:57:52.6857175Z", + "lastModifiedBy": "fake@hotmail.com", + "lastModifiedByType": "User" + }, + "provisioningState": "Succeeded", + "properties": { + "type": "generic", + "data": { + "tls.crt": { + "encoding": "raw", + "value": "tls.crt" + }, + "tls.key": { + "encoding": "base64", + "value": "dGxzLmNlcnQK" + }, + "servicePrincipalPassword": { + "value": "10000000-1000-1000-0000-000000000000" + } + } + }, + "tenantId": "00000000-0000-0000-0000-000000000000", + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "resourceGroup": "testGroup", + "createdApiVersion": "2023-10-01-preview", + "updatedApiVersion": "2023-10-01-preview" + } \ No newline at end of file diff --git a/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_invalid_resource.json b/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_invalid_resource.json new file mode 100644 index 0000000000..580eaa5d47 --- /dev/null +++ b/pkg/corerp/frontend/controller/secretstores/testdata/secretstores_datamodel_global_scope_invalid_resource.json @@ -0,0 +1,37 @@ +{ + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/secretStores/secret0", + "name": "secret0", + "type": "applications.core/secretstores", + "location": "global", + "systemData": { + "createdAt": "2022-03-22T18:54:52.6857175Z", + "createdBy": "fake@hotmail.com", + "createdByType": "User", + "lastModifiedAt": "2022-03-22T18:57:52.6857175Z", + "lastModifiedBy": "fake@hotmail.com", + "lastModifiedByType": "User" + }, + "provisioningState": "Succeeded", + "properties": { + "resource": "secret0", + "type": "generic", + "data": { + "tls.crt": { + "encoding": "raw", + "value": "tls.crt" + }, + "tls.key": { + "encoding": "base64", + "value": "dGxzLmNlcnQK" + }, + "servicePrincipalPassword": { + "value": "10000000-1000-1000-0000-000000000000" + } + } + }, + "tenantId": "00000000-0000-0000-0000-000000000000", + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "resourceGroup": "testGroup", + "createdApiVersion": "2023-10-01-preview", + "updatedApiVersion": "2023-10-01-preview" + } \ No newline at end of file diff --git a/pkg/rp/v1/types.go b/pkg/rp/v1/types.go index 796bcc36df..ab7dcae945 100644 --- a/pkg/rp/v1/types.go +++ b/pkg/rp/v1/types.go @@ -55,6 +55,11 @@ func (b *BasicResourceProperties) EqualLinkedResource(prop *BasicResourcePropert return strings.EqualFold(b.Application, prop.Application) && strings.EqualFold(b.Environment, prop.Environment) } +// Method IsGlobalScopedResource checks if resource is global scoped. +func (b *BasicResourceProperties) IsGlobalScopedResource() bool { + return b.Application == "" && b.Environment == "" +} + // ResourceStatus represents the output status of Radius resource. type ResourceStatus struct { // Compute represents a resource presented in the underlying platform. diff --git a/pkg/rp/v1/types_test.go b/pkg/rp/v1/types_test.go index 84d7befb7c..8d6ad5da8b 100644 --- a/pkg/rp/v1/types_test.go +++ b/pkg/rp/v1/types_test.go @@ -96,3 +96,38 @@ func TestEqualLinkedResource(t *testing.T) { require.Equal(t, tt.propA.EqualLinkedResource(&tt.propB), tt.eq) } } + +func Test_isGlobalScopedResource(t *testing.T) { + tests := []struct { + desc string + basicResourceProperties BasicResourceProperties + isGlobal bool + }{ + { + desc: "application scope", + basicResourceProperties: BasicResourceProperties{ + Application: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/app1", + }, + isGlobal: false, + }, + { + desc: "environment scope", + basicResourceProperties: BasicResourceProperties{ + Environment: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.core/environments/env0", + }, + isGlobal: false, + }, + { + desc: "global scope", + basicResourceProperties: BasicResourceProperties{}, + isGlobal: true, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + act := tt.basicResourceProperties.IsGlobalScopedResource() + require.Equal(t, act, tt.isGlobal) + }) + } + +} diff --git a/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/examples/SecretStores_CreateOrUpdate_GlobalScope.json b/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/examples/SecretStores_CreateOrUpdate_GlobalScope.json new file mode 100644 index 0000000000..de3ab2d199 --- /dev/null +++ b/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/examples/SecretStores_CreateOrUpdate_GlobalScope.json @@ -0,0 +1,49 @@ +{ + "operationId": "SecretStores_CreateOrUpdate", + "title": "Create or Update a secret store resource with global scope", + "parameters": { + "rootScope": "/planes/radius/local/resourceGroups/testGroup", + "secretStoreName": "secret", + "api-version": "2023-10-01-preview", + "SecretStoreResource": { + "location": "global", + "properties": { + "type": "certificate", + "data": { + "tls.crt": { + "encoding": "base64", + "value": "certificate" + }, + "tls.key": { + "encoding": "base64", + "value": "certificate" + } + }, + "resource": "testNamespace/secret" + } + } + }, + "responses": { + "200": { + "body": { + "id": "/planes/radius/local/resourceGroups/testGroup/providers/Applications.Core/secretStores/secret", + "name": "secret", + "type": "Applications.Core/secretStores", + "location": "global", + "properties": { + "provisioningState": "Succeeded", + "type": "certificate", + "data": { + "tls.crt": { + "encoding": "base64" + }, + "tls.key": { + "encoding": "base64" + } + }, + "resource": "testNamespace/secret" + } + } + } + } + } \ No newline at end of file diff --git a/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json b/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json index e3bd250f4e..83c5db3559 100644 --- a/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json +++ b/swagger/specification/applications/resource-manager/Applications.Core/preview/2023-10-01-preview/openapi.json @@ -2002,6 +2002,9 @@ }, "Create or Update a secret store resource with valueFrom": { "$ref": "./examples/SecretStores_CreateOrUpdateValueFrom.json" + }, + "Create or Update a secret store resource with global scope": { + "$ref": "./examples/SecretStores_CreateOrUpdate_GlobalScope.json" } }, "x-ms-long-running-operation-options": { @@ -5059,7 +5062,6 @@ } }, "required": [ - "application", "data" ] }, diff --git a/typespec/Applications.Core/examples/2023-10-01-preview/SecretStores_CreateOrUpdate_GlobalScope.json b/typespec/Applications.Core/examples/2023-10-01-preview/SecretStores_CreateOrUpdate_GlobalScope.json new file mode 100644 index 0000000000..de3ab2d199 --- /dev/null +++ b/typespec/Applications.Core/examples/2023-10-01-preview/SecretStores_CreateOrUpdate_GlobalScope.json @@ -0,0 +1,49 @@ +{ + "operationId": "SecretStores_CreateOrUpdate", + "title": "Create or Update a secret store resource with global scope", + "parameters": { + "rootScope": "/planes/radius/local/resourceGroups/testGroup", + "secretStoreName": "secret", + "api-version": "2023-10-01-preview", + "SecretStoreResource": { + "location": "global", + "properties": { + "type": "certificate", + "data": { + "tls.crt": { + "encoding": "base64", + "value": "certificate" + }, + "tls.key": { + "encoding": "base64", + "value": "certificate" + } + }, + "resource": "testNamespace/secret" + } + } + }, + "responses": { + "200": { + "body": { + "id": "/planes/radius/local/resourceGroups/testGroup/providers/Applications.Core/secretStores/secret", + "name": "secret", + "type": "Applications.Core/secretStores", + "location": "global", + "properties": { + "provisioningState": "Succeeded", + "type": "certificate", + "data": { + "tls.crt": { + "encoding": "base64" + }, + "tls.key": { + "encoding": "base64" + } + }, + "resource": "testNamespace/secret" + } + } + } + } + } \ No newline at end of file diff --git a/typespec/Applications.Core/secretstores.tsp b/typespec/Applications.Core/secretstores.tsp index dee0ba96ca..09b128ae93 100644 --- a/typespec/Applications.Core/secretstores.tsp +++ b/typespec/Applications.Core/secretstores.tsp @@ -47,7 +47,7 @@ model SecretStoreResource is TrackedResourceRequired