From 8dab28e736d696a431f099d66a5572fa0ddbfe07 Mon Sep 17 00:00:00 2001 From: ytimocin Date: Tue, 20 Feb 2024 13:49:42 -0800 Subject: [PATCH] Initial work on adding support for the multiple TF Providers Signed-off-by: ytimocin --- .../2023-10-01-preview/types.json | 2 +- hack/bicep-types-radius/generated/index.json | 2 +- .../src/generator/package.json | 2 +- .../environment_conversion.go | 109 ++++++++- .../environment_conversion_test.go | 224 +++++++++++++++++- ...propertiesdatamodel-insecure-registry.json | 26 +- ...opertiesdatamodel-missingtemplatekind.json | 4 +- ...ntrecipepropertiesdatamodel-terraform.json | 26 +- .../environmentrecipepropertiesdatamodel.json | 4 +- ...ironmentresource-invalid-resourcetype.json | 46 ++-- ...ironmentresource-invalid-templatekind.json | 42 ++-- ...ironmentresource-missing-templatekind.json | 40 ++-- ...entresource-terraformrecipe-localpath.json | 42 ++-- ...onmentresource-with-workload-identity.json | 11 +- .../testdata/environmentresource.json | 48 +++- ...ourcedatamodel-with-workload-identity.json | 10 +- .../environmentresourcedatamodel.json | 42 +++- .../environmentresourcedatamodelemptyext.json | 94 ++++---- ...entresourcedatamodelemptytemplatekind.json | 62 ++--- .../testdata/environmentresourceemptyext.json | 60 ++--- .../environmentresourceemptyext2.json | 56 ++--- .../testdata/extender_manual_nosecrets.json | 4 +- .../extenderdatamodel_manual_nosecrets.json | 6 +- .../v20231001preview/zz_generated_models.go | 77 ++++-- .../zz_generated_models_serde.go | 123 ++++++++++ pkg/corerp/datamodel/recipe_types.go | 32 +++ pkg/recipes/controllerconfig/config.go | 2 +- pkg/recipes/driver/terraform.go | 16 +- pkg/recipes/driver/terraform_test.go | 2 +- pkg/recipes/terraform/execute.go | 17 +- pkg/recipes/terraform/execute_test.go | 6 +- .../preview/2023-10-01-preview/openapi.json | 109 +++++++-- typespec/Applications.Core/containers.tsp | 3 +- typespec/Applications.Core/environments.tsp | 62 +++-- typespec/Applications.Core/extenders.tsp | 3 +- 35 files changed, 1053 insertions(+), 361 deletions(-) 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 21b07689dea..d2de05ef56a 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":153,"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."},"recipeConfig":{"Type":146,"Flags":0,"Description":"Configuration for Recipes. Defines how each type of Recipe should be configured and run."},"extensions":{"Type":152,"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}},{"2":{"Name":"RecipeConfigProperties","Properties":{"terraform":{"Type":147,"Flags":0,"Description":"Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as part of Recipe deployment."}}}},{"2":{"Name":"TerraformConfigProperties","Properties":{"authentication":{"Type":148,"Flags":0,"Description":"Authentication information used to access private Terraform module sources. Supported module sources: Git."}}}},{"2":{"Name":"AuthConfig","Properties":{"git":{"Type":149,"Flags":0,"Description":"Authentication information used to access private Terraform modules from Git repository sources."}}}},{"2":{"Name":"GitAuthConfig","Properties":{"pat":{"Type":151,"Flags":0,"Description":"Personal Access Token (PAT) configuration used to authenticate to Git platforms."}}}},{"2":{"Name":"SecretConfig","Properties":{"secret":{"Type":4,"Flags":0,"Description":"The ID of an Applications.Core/SecretStore resource containing the Git platform personal access token (PAT). The secret store must have a secret named 'pat', containing the PAT value. A secret named 'username' is optional, containing the username associated with the pat. By default no username is specified."}}}},{"2":{"Name":"GitAuthConfigPat","Properties":{},"AdditionalProperties":150}},{"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":155,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":156,"Flags":10,"Description":"The resource api version"},"properties":{"Type":158,"Flags":1,"Description":"ExtenderResource portable resource properties"},"tags":{"Type":171,"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":166,"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":167,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":170,"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":[159,160,161,162,163,164,165]}},{"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":[168,169]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/extenders@2023-10-01-preview","ScopeType":0,"Body":157}},{"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":173,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":174,"Flags":10,"Description":"The resource api version"},"properties":{"Type":176,"Flags":1,"Description":"Gateway properties"},"tags":{"Type":192,"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":184,"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":185,"Flags":0,"Description":"Declare hostname information for the Gateway. Leaving the hostname empty auto-assigns one: mygateway.myapp.PUBLICHOSTNAMEORIP.nip.io."},"routes":{"Type":187,"Flags":1,"Description":"Routes attached to this Gateway"},"tls":{"Type":188,"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":[177,178,179,180,181,182,183]}},{"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":186}},{"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":191,"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":[189,190]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/gateways@2023-10-01-preview","ScopeType":0,"Body":175}},{"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":194,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":195,"Flags":10,"Description":"The resource api version"},"properties":{"Type":197,"Flags":1,"Description":"HTTPRoute properties"},"tags":{"Type":206,"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":205,"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":[198,199,200,201,202,203,204]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/httpRoutes@2023-10-01-preview","ScopeType":0,"Body":196}},{"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":208,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":209,"Flags":10,"Description":"The resource api version"},"properties":{"Type":211,"Flags":1,"Description":"The properties of SecretStore"},"tags":{"Type":229,"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":219,"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":222,"Flags":0,"Description":"The type of SecretStore data"},"data":{"Type":228,"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":[212,213,214,215,216,217,218]}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[220,221]}},{"2":{"Name":"SecretValueProperties","Properties":{"encoding":{"Type":226,"Flags":0,"Description":"The type of SecretValue Encoding"},"value":{"Type":4,"Flags":0,"Description":"The value of secret."},"valueFrom":{"Type":227,"Flags":0,"Description":"The Secret value source properties"}}}},{"6":{"Value":"raw"}},{"6":{"Value":"base64"}},{"5":{"Elements":[224,225]}},{"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":223}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/secretStores@2023-10-01-preview","ScopeType":0,"Body":210}},{"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":231,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":232,"Flags":10,"Description":"The resource api version"},"properties":{"Type":234,"Flags":1,"Description":"Volume properties"},"tags":{"Type":266,"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":242,"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":243}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[235,236,237,238,239,240,241]}},{"2":{"Name":"AzureKeyVaultVolumeProperties","Properties":{"certificates":{"Type":256,"Flags":0,"Description":"The KeyVault certificates that this volume exposes"},"keys":{"Type":258,"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":264,"Flags":0,"Description":"The KeyVault secrets that this volume exposes"},"kind":{"Type":265,"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":248,"Flags":0,"Description":"Represents secret encodings"},"format":{"Type":251,"Flags":0,"Description":"Represents certificate formats"},"name":{"Type":4,"Flags":1,"Description":"The name of the certificate"},"certType":{"Type":255,"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":[245,246,247]}},{"6":{"Value":"pem"}},{"6":{"Value":"pfx"}},{"5":{"Elements":[249,250]}},{"6":{"Value":"certificate"}},{"6":{"Value":"privatekey"}},{"6":{"Value":"publickey"}},{"5":{"Elements":[252,253,254]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesCertificates","Properties":{},"AdditionalProperties":244}},{"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":257}},{"2":{"Name":"SecretObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":263,"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":[260,261,262]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesSecrets","Properties":{},"AdditionalProperties":259}},{"6":{"Value":"azure.com.keyvault"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/volumes@2023-10-01-preview","ScopeType":0,"Body":233}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/extenders","ApiVersion":"2023-10-01-preview","Output":0,"Input":0}},{"2":{"Name":"SecretStoreListSecretsResult","Properties":{"type":{"Type":272,"Flags":2,"Description":"The type of SecretStore data"},"data":{"Type":273,"Flags":2,"Description":"An object to represent key-value type secrets"}}}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[270,271]}},{"2":{"Name":"SecretStoreListSecretsResultData","Properties":{},"AdditionalProperties":223}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/secretStores","ApiVersion":"2023-10-01-preview","Output":269,"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":160,"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."},"recipeConfig":{"Type":146,"Flags":0,"Description":"Configuration for Recipes. Defines how each type of Recipe should be configured and run."},"extensions":{"Type":159,"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}},{"2":{"Name":"RecipeConfigProperties","Properties":{"terraform":{"Type":147,"Flags":0,"Description":"Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as part of Recipe deployment."},"envVariables":{"Type":157,"Flags":0,"Description":"EnvironmentVariables describes structure enabling environment variables to be set."}}}},{"2":{"Name":"TerraformConfigProperties","Properties":{"authentication":{"Type":148,"Flags":0,"Description":"Authentication information used to access private Terraform module sources. Supported module sources: Git."},"providers":{"Type":156,"Flags":0,"Description":"Specifies the details of Terraform providers."}}}},{"2":{"Name":"AuthConfig","Properties":{"git":{"Type":149,"Flags":0,"Description":"Authentication information used to access private Terraform modules from Git repository sources."}}}},{"2":{"Name":"GitAuthConfig","Properties":{"pat":{"Type":151,"Flags":0,"Description":"Personal Access Token (PAT) configuration used to authenticate to Git platforms."}}}},{"2":{"Name":"SecretConfig","Properties":{"secret":{"Type":4,"Flags":0,"Description":"The ID of an Applications.Core/SecretStore resource containing the Git platform personal access token (PAT). The secret store must have a secret named 'pat', containing the PAT value. A secret named 'username' is optional, containing the username associated with the pat. By default no username is specified."}}}},{"2":{"Name":"GitAuthConfigPat","Properties":{},"AdditionalProperties":150}},{"2":{"Name":"ProviderConfigProperties","Properties":{"secrets":{"Type":154,"Flags":0,"Description":"The secrets for the referenced provider resource."}},"AdditionalProperties":0}},{"2":{"Name":"RecipeSecret","Properties":{"source":{"Type":4,"Flags":1,"Description":"The resource id for the secret store containing credentials."},"key":{"Type":4,"Flags":1,"Description":"The key for the secret in the secret store."}}}},{"2":{"Name":"ProviderConfigPropertiesSecrets","Properties":{},"AdditionalProperties":153}},{"3":{"ItemType":152}},{"2":{"Name":"TerraformConfigPropertiesProviders","Properties":{},"AdditionalProperties":155}},{"2":{"Name":"EnvironmentVariables","Properties":{"secrets":{"Type":158,"Flags":0,"Description":"The provider secrets passed as environment variables."}},"AdditionalProperties":0}},{"2":{"Name":"EnvironmentVariablesSecrets","Properties":{},"AdditionalProperties":153}},{"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":162,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":163,"Flags":10,"Description":"The resource api version"},"properties":{"Type":165,"Flags":1,"Description":"ExtenderResource portable resource properties"},"tags":{"Type":178,"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":173,"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":174,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":177,"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":[166,167,168,169,170,171,172]}},{"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":[175,176]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/extenders@2023-10-01-preview","ScopeType":0,"Body":164}},{"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":180,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":181,"Flags":10,"Description":"The resource api version"},"properties":{"Type":183,"Flags":1,"Description":"Gateway properties"},"tags":{"Type":199,"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":191,"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":192,"Flags":0,"Description":"Declare hostname information for the Gateway. Leaving the hostname empty auto-assigns one: mygateway.myapp.PUBLICHOSTNAMEORIP.nip.io."},"routes":{"Type":194,"Flags":1,"Description":"Routes attached to this Gateway"},"tls":{"Type":195,"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":[184,185,186,187,188,189,190]}},{"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":193}},{"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":198,"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":[196,197]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/gateways@2023-10-01-preview","ScopeType":0,"Body":182}},{"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":201,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":202,"Flags":10,"Description":"The resource api version"},"properties":{"Type":204,"Flags":1,"Description":"HTTPRoute properties"},"tags":{"Type":213,"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":212,"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":[205,206,207,208,209,210,211]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/httpRoutes@2023-10-01-preview","ScopeType":0,"Body":203}},{"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":215,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":216,"Flags":10,"Description":"The resource api version"},"properties":{"Type":218,"Flags":1,"Description":"The properties of SecretStore"},"tags":{"Type":236,"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":226,"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":229,"Flags":0,"Description":"The type of SecretStore data"},"data":{"Type":235,"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":[219,220,221,222,223,224,225]}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[227,228]}},{"2":{"Name":"SecretValueProperties","Properties":{"encoding":{"Type":233,"Flags":0,"Description":"The type of SecretValue Encoding"},"value":{"Type":4,"Flags":0,"Description":"The value of secret."},"valueFrom":{"Type":234,"Flags":0,"Description":"The Secret value source properties"}}}},{"6":{"Value":"raw"}},{"6":{"Value":"base64"}},{"5":{"Elements":[231,232]}},{"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":230}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/secretStores@2023-10-01-preview","ScopeType":0,"Body":217}},{"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":238,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":239,"Flags":10,"Description":"The resource api version"},"properties":{"Type":241,"Flags":1,"Description":"Volume properties"},"tags":{"Type":273,"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":249,"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":250}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[242,243,244,245,246,247,248]}},{"2":{"Name":"AzureKeyVaultVolumeProperties","Properties":{"certificates":{"Type":263,"Flags":0,"Description":"The KeyVault certificates that this volume exposes"},"keys":{"Type":265,"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":271,"Flags":0,"Description":"The KeyVault secrets that this volume exposes"},"kind":{"Type":272,"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":255,"Flags":0,"Description":"Represents secret encodings"},"format":{"Type":258,"Flags":0,"Description":"Represents certificate formats"},"name":{"Type":4,"Flags":1,"Description":"The name of the certificate"},"certType":{"Type":262,"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":[252,253,254]}},{"6":{"Value":"pem"}},{"6":{"Value":"pfx"}},{"5":{"Elements":[256,257]}},{"6":{"Value":"certificate"}},{"6":{"Value":"privatekey"}},{"6":{"Value":"publickey"}},{"5":{"Elements":[259,260,261]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesCertificates","Properties":{},"AdditionalProperties":251}},{"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":264}},{"2":{"Name":"SecretObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":270,"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":[267,268,269]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesSecrets","Properties":{},"AdditionalProperties":266}},{"6":{"Value":"azure.com.keyvault"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/volumes@2023-10-01-preview","ScopeType":0,"Body":240}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/extenders","ApiVersion":"2023-10-01-preview","Output":0,"Input":0}},{"2":{"Name":"SecretStoreListSecretsResult","Properties":{"type":{"Type":279,"Flags":2,"Description":"The type of SecretStore data"},"data":{"Type":280,"Flags":2,"Description":"An object to represent key-value type secrets"}}}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[277,278]}},{"2":{"Name":"SecretStoreListSecretsResultData","Properties":{},"AdditionalProperties":230}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/secretStores","ApiVersion":"2023-10-01-preview","Output":276,"Input":0}}] \ No newline at end of file diff --git a/hack/bicep-types-radius/generated/index.json b/hack/bicep-types-radius/generated/index.json index 927e764089a..cc561d5a60c 100644 --- a/hack/bicep-types-radius/generated/index.json +++ b/hack/bicep-types-radius/generated/index.json @@ -1 +1 @@ -{"Resources":{"Applications.Core/applications@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":58},"Applications.Core/containers@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":123},"Applications.Core/environments@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":154},"Applications.Core/extenders@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":172},"Applications.Core/gateways@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":193},"Applications.Core/httpRoutes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":207},"Applications.Core/secretStores@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":230},"Applications.Core/volumes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":267},"Applications.Dapr/pubSubBrokers@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":49},"Applications.Dapr/secretStores@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":66},"Applications.Dapr/stateStores@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":84},"Applications.Datastores/mongoDatabases@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":50},"Applications.Datastores/redisCaches@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":69},"Applications.Datastores/sqlDatabases@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":88},"Applications.Messaging/rabbitMQQueues@2023-10-01-preview":{"RelativePath":"applications/applications.messaging/2023-10-01-preview/types.json","Index":50}},"Functions":{"applications.core/extenders":{"2023-10-01-preview":[{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":268}]},"applications.core/secretstores":{"2023-10-01-preview":[{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":274}]},"applications.datastores/mongodatabases":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":90}]},"applications.datastores/rediscaches":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":92}]},"applications.datastores/sqldatabases":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":94}]},"applications.messaging/rabbitmqqueues":{"2023-10-01-preview":[{"RelativePath":"applications/applications.messaging/2023-10-01-preview/types.json","Index":52}]}}} \ No newline at end of file +{"Resources":{"Applications.Core/applications@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":58},"Applications.Core/containers@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":123},"Applications.Core/environments@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":161},"Applications.Core/extenders@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":179},"Applications.Core/gateways@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":200},"Applications.Core/httpRoutes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":214},"Applications.Core/secretStores@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":237},"Applications.Core/volumes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":274},"Applications.Dapr/pubSubBrokers@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":49},"Applications.Dapr/secretStores@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":66},"Applications.Dapr/stateStores@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":84},"Applications.Datastores/mongoDatabases@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":50},"Applications.Datastores/redisCaches@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":69},"Applications.Datastores/sqlDatabases@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":88},"Applications.Messaging/rabbitMQQueues@2023-10-01-preview":{"RelativePath":"applications/applications.messaging/2023-10-01-preview/types.json","Index":50}},"Functions":{"applications.core/extenders":{"2023-10-01-preview":[{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":275}]},"applications.core/secretstores":{"2023-10-01-preview":[{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":281}]},"applications.datastores/mongodatabases":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":90}]},"applications.datastores/rediscaches":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":92}]},"applications.datastores/sqldatabases":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":94}]},"applications.messaging/rabbitmqqueues":{"2023-10-01-preview":[{"RelativePath":"applications/applications.messaging/2023-10-01-preview/types.json","Index":52}]}}} \ No newline at end of file diff --git a/hack/bicep-types-radius/src/generator/package.json b/hack/bicep-types-radius/src/generator/package.json index 8aa7198dd83..7c98d35f1bc 100644 --- a/hack/bicep-types-radius/src/generator/package.json +++ b/hack/bicep-types-radius/src/generator/package.json @@ -45,4 +45,4 @@ "typescript": "^4.6.3", "yargs": "^17.4.0" } -} +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/environment_conversion.go b/pkg/corerp/api/v20231001preview/environment_conversion.go index a5d2ff2d6fd..6fdd9a1848e 100644 --- a/pkg/corerp/api/v20231001preview/environment_conversion.go +++ b/pkg/corerp/api/v20231001preview/environment_conversion.go @@ -39,7 +39,6 @@ const ( // ConvertTo converts from the versioned Environment resource to version-agnostic datamodel. func (src *EnvironmentResource) ConvertTo() (v1.DataModelInterface, error) { // Note: SystemData conversion isn't required since this property comes ARM and datastore. - converted := &datamodel.Environment{ BaseResource: v1.BaseResource{ TrackedResource: v1.TrackedResource{ @@ -204,9 +203,15 @@ func toRecipeConfigDatamodel(config *RecipeConfigProperties) datamodel.RecipeCon } } } + + recipeConfig.Terraform.Providers = toRecipeConfigTerraformProvidersDatamodel(config) } + + recipeConfig.EnvVariables = toRecipeConfigEnvDatamodel(config) + return recipeConfig } + return datamodel.RecipeConfigProperties{} } @@ -229,9 +234,15 @@ func fromRecipeConfigDatamodel(config datamodel.RecipeConfigProperties) *RecipeC } } } + + recipeConfig.Terraform.Providers = fromRecipeConfigTerraformProvidersDatamodel(config) } + + recipeConfig.EnvVariables = fromRecipeConfigEnvDatamodel(config) + return recipeConfig } + return nil } @@ -395,3 +406,99 @@ func fromRecipePropertiesClassificationDatamodel(e datamodel.EnvironmentRecipePr } return nil } + +func toRecipeConfigTerraformProvidersDatamodel(config *RecipeConfigProperties) map[string][]datamodel.ProviderConfigProperties { + if config.Terraform == nil || config.Terraform.Providers == nil { + return nil + } + + dm := map[string][]datamodel.ProviderConfigProperties{} + + for k, v := range config.Terraform.Providers { + dm[k] = []datamodel.ProviderConfigProperties{} + + for _, provider := range v { + secrets := map[string]datamodel.RecipeSecret{} + for secretKey, secret := range provider.Secrets { + if secret.Source == nil || secret.Key == nil { + continue + } + + secrets[secretKey] = datamodel.RecipeSecret{ + Source: *secret.Source, + Key: *secret.Key, + } + } + + dm[k] = append(dm[k], datamodel.ProviderConfigProperties{ + AdditionalProperties: provider.AdditionalProperties, + Secrets: secrets, + }) + } + } + + return dm +} + +func fromRecipeConfigTerraformProvidersDatamodel(config datamodel.RecipeConfigProperties) map[string][]*ProviderConfigProperties { + if config.Terraform.Providers == nil { + return nil + } + + providers := map[string][]*ProviderConfigProperties{} + + for k, v := range config.Terraform.Providers { + providers[k] = []*ProviderConfigProperties{} + + for _, provider := range v { + secrets := map[string]*RecipeSecret{} + for secretKey, secret := range provider.Secrets { + secrets[secretKey] = &RecipeSecret{ + Source: to.Ptr(secret.Source), + Key: to.Ptr(secret.Key), + } + } + + providers[k] = append(providers[k], &ProviderConfigProperties{ + AdditionalProperties: provider.AdditionalProperties, + Secrets: secrets, + }) + } + } + + return providers +} + +func toRecipeConfigEnvDatamodel(config *RecipeConfigProperties) datamodel.EnvironmentVariables { + if config.EnvVariables == nil { + return datamodel.EnvironmentVariables{} + } + + secrets := make(map[string]datamodel.RecipeSecret, len(config.EnvVariables.Secrets)) + for k, v := range config.EnvVariables.Secrets { + secrets[k] = datamodel.RecipeSecret{ + Source: to.String(v.Source), + Key: to.String(v.Key), + } + } + + return datamodel.EnvironmentVariables{ + AdditionalProperties: config.EnvVariables.AdditionalProperties, + Secrets: secrets, + } +} + +func fromRecipeConfigEnvDatamodel(config datamodel.RecipeConfigProperties) *EnvironmentVariables { + secrets := make(map[string]*RecipeSecret, len(config.EnvVariables.Secrets)) + for k, v := range config.EnvVariables.Secrets { + secrets[k] = &RecipeSecret{ + Source: to.Ptr(v.Source), + Key: to.Ptr(v.Key), + } + } + + return &EnvironmentVariables{ + AdditionalProperties: config.EnvVariables.AdditionalProperties, + Secrets: secrets, + } +} diff --git a/pkg/corerp/api/v20231001preview/environment_conversion_test.go b/pkg/corerp/api/v20231001preview/environment_conversion_test.go index 68d61c70509..27ce98ce5bc 100644 --- a/pkg/corerp/api/v20231001preview/environment_conversion_test.go +++ b/pkg/corerp/api/v20231001preview/environment_conversion_test.go @@ -76,9 +76,13 @@ func TestConvertVersionedToDataModel(t *testing.T) { RecipeConfig: datamodel.RecipeConfigProperties{ Terraform: datamodel.TerraformConfigProperties{ Authentication: datamodel.AuthConfig{ - Git: datamodel.GitAuthConfig{}, + Git: datamodel.GitAuthConfig{ + PAT: map[string]datamodel.SecretConfig{}, + }, }, + Providers: map[string][]datamodel.ProviderConfigProperties{}, }, + EnvVariables: datamodel.EnvironmentVariables{}, }, Recipes: map[string]map[string]datamodel.EnvironmentRecipeProperties{ ds_ctrl.MongoDatabasesResourceType: { @@ -135,6 +139,40 @@ func TestConvertVersionedToDataModel(t *testing.T) { }, }, }, + Providers: map[string][]datamodel.ProviderConfigProperties{ + "azurerm": { + { + AdditionalProperties: map[string]any{ + "subscriptionId": "00000000-0000-0000-0000-000000000000", + }, + Secrets: map[string]datamodel.RecipeSecret{ + "my_secret_1": { + Source: "source.my_secret_1", + Key: "secret.one", + }, + "my_secret_2": { + Source: "source.my_secret_2", + Key: "secret.two", + }, + }, + }, + }, + }, + }, + EnvVariables: datamodel.EnvironmentVariables{ + AdditionalProperties: map[string]any{ + "myEnvVar": "myEnvValue", + }, + Secrets: map[string]datamodel.RecipeSecret{ + "my_secret_1": { + Source: "source.my_secret_1", + Key: "secret.one", + }, + "my_secret_2": { + Source: "source.my_secret_2", + Key: "secret.two", + }, + }, }, }, Recipes: map[string]map[string]datamodel.EnvironmentRecipeProperties{ @@ -395,6 +433,15 @@ func TestConvertDataModelToVersioned(t *testing.T) { case *BicepRecipeProperties: require.Equal(t, true, bool(*c.PlainHTTP)) } + require.Equal(t, 1, len(versioned.Properties.RecipeConfig.Terraform.Providers)) + require.Equal(t, 1, len(versioned.Properties.RecipeConfig.Terraform.Providers["azurerm"])) + azurermProvider := versioned.Properties.RecipeConfig.Terraform.Providers["azurerm"][0] + subscriptionId := azurermProvider.AdditionalProperties["subscriptionId"] + require.Equal(t, "00000000-0000-0000-0000-000000000000", subscriptionId) + require.Equal(t, 1, len(azurermProvider.Secrets)) + require.Equal(t, 1, len(versioned.Properties.RecipeConfig.EnvVariables.AdditionalProperties)) + require.Equal(t, "myEnvValue", versioned.Properties.RecipeConfig.EnvVariables.AdditionalProperties["myEnvVar"]) + require.Equal(t, 2, len(versioned.Properties.RecipeConfig.EnvVariables.Secrets)) } if tt.filename == "environmentresourcedatamodelemptyext.json" { switch c := recipeDetails.(type) { @@ -545,3 +592,178 @@ func getTestKubernetesEmptyMetadataExtensions(t *testing.T) []datamodel.Extensio return extensions } + +func Test_toRecipeConfigTerraformProvidersDatamodel(t *testing.T) { + tests := []struct { + name string + config *RecipeConfigProperties + want map[string][]datamodel.ProviderConfigProperties + }{ + { + name: "empty", + config: &RecipeConfigProperties{}, + want: nil, + }, + { + name: "single provider", + config: &RecipeConfigProperties{ + Terraform: &TerraformConfigProperties{ + Providers: map[string][]*ProviderConfigProperties{ + "azurerm": { + { + AdditionalProperties: map[string]any{ + "subscription_id": "00000000-0000-0000-0000-000000000000", + }, + Secrets: map[string]*RecipeSecret{ + "my_secret_1": { + Source: to.Ptr("my_secret_1"), + Key: to.Ptr("my_key_1"), + }, + }, + }, + }, + }, + }, + }, + want: map[string][]datamodel.ProviderConfigProperties{ + "azurerm": { + { + AdditionalProperties: map[string]any{ + "subscription_id": "00000000-0000-0000-0000-000000000000", + }, + Secrets: map[string]datamodel.RecipeSecret{ + "my_secret_1": { + Source: "my_secret_1", + Key: "my_key_1", + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := toRecipeConfigTerraformProvidersDatamodel(tt.config) + require.Equal(t, tt.want, result) + }) + } +} + +func Test_fromRecipeConfigTerraformProvidersDatamodel(t *testing.T) { + tests := []struct { + name string + config datamodel.RecipeConfigProperties + want map[string][]*ProviderConfigProperties + }{ + { + name: "empty", + config: datamodel.RecipeConfigProperties{}, + want: nil, + }, + { + name: "single provider", + config: datamodel.RecipeConfigProperties{ + Terraform: datamodel.TerraformConfigProperties{ + Providers: map[string][]datamodel.ProviderConfigProperties{ + "azurerm": { + { + AdditionalProperties: map[string]any{ + "subscription_id": "00000000-0000-0000-0000-000000000000", + }, + Secrets: map[string]datamodel.RecipeSecret{ + "my_secret_1": { + Source: "my_secret_1", + Key: "my_key_1", + }, + }, + }, + }, + }, + }, + }, + want: map[string][]*ProviderConfigProperties{ + "azurerm": { + { + AdditionalProperties: map[string]any{ + "subscription_id": "00000000-0000-0000-0000-000000000000", + }, + Secrets: map[string]*RecipeSecret{ + "my_secret_1": { + Source: to.Ptr("my_secret_1"), + Key: to.Ptr("my_key_1"), + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := fromRecipeConfigTerraformProvidersDatamodel(tt.config) + require.Equal(t, tt.want, result) + }) + } +} + +func Test_toRecipeConfigEnvDatamodel(t *testing.T) { + tests := []struct { + name string + config *RecipeConfigProperties + want datamodel.EnvironmentVariables + }{ + { + name: "empty", + config: &RecipeConfigProperties{}, + want: datamodel.EnvironmentVariables{}, + }, + { + name: "single provider", + config: &RecipeConfigProperties{ + EnvVariables: &EnvironmentVariables{ + AdditionalProperties: map[string]any{ + "key1": "value1", + "key2": "value2", + }, + }, + }, + want: datamodel.EnvironmentVariables{ + AdditionalProperties: map[string]any{ + "key1": "value1", + "key2": "value2", + }, + Secrets: map[string]datamodel.RecipeSecret{}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := toRecipeConfigEnvDatamodel(tt.config) + require.Equal(t, tt.want, result) + }) + } +} + +func Test_fromRecipeConfigEnvDatamodel(t *testing.T) { + tests := []struct { + name string + config datamodel.RecipeConfigProperties + want *EnvironmentVariables + }{ + { + name: "empty", + config: datamodel.RecipeConfigProperties{}, + want: &EnvironmentVariables{ + Secrets: map[string]*RecipeSecret{}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := fromRecipeConfigEnvDatamodel(tt.config) + require.Equal(t, tt.want, result) + }) + } +} diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-insecure-registry.json b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-insecure-registry.json index 8f78c51cc74..4d067f29bc3 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-insecure-registry.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-insecure-registry.json @@ -1,15 +1,15 @@ { - "templateKind": "bicep", - "templatePath": "br:localhost:8000/recipes/cosmosdb", - "plainHttp": true, - "parameters": { - "throughput": { - "maxValue": 400, - "defaultValue": 200 - }, - "location": { - "type" : "string", - "defaultValue" : "[resourceGroup().location]" - } + "templateKind": "bicep", + "templatePath": "br:localhost:8000/recipes/cosmosdb", + "plainHttp": true, + "parameters": { + "throughput": { + "maxValue": 400, + "defaultValue": 200 + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-missingtemplatekind.json b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-missingtemplatekind.json index 62b803a7a6a..f6ff6c41aa6 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-missingtemplatekind.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-missingtemplatekind.json @@ -6,8 +6,8 @@ "defaultValue": 200 }, "location": { - "type" : "string", - "defaultValue" : "[resourceGroup().location]" + "type": "string", + "defaultValue": "[resourceGroup().location]" } } } \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-terraform.json b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-terraform.json index d761b3a2c88..6797d03b414 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-terraform.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel-terraform.json @@ -1,15 +1,15 @@ { - "templateKind": "terraform", - "templatePath": "Azure/cosmosdb/azurerm", - "terraformVersion": "1.1.0", - "parameters": { - "throughput": { - "maxValue": 400, - "defaultValue": 200 - }, - "location": { - "type" : "string", - "defaultValue" : "[resourceGroup().location]" - } + "templateKind": "terraform", + "templatePath": "Azure/cosmosdb/azurerm", + "terraformVersion": "1.1.0", + "parameters": { + "throughput": { + "maxValue": 400, + "defaultValue": 200 + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel.json b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel.json index c983da8df91..743f8e1dc08 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentrecipepropertiesdatamodel.json @@ -7,8 +7,8 @@ "defaultValue": 200 }, "location": { - "type" : "string", - "defaultValue" : "[resourceGroup().location]" + "type": "string", + "defaultValue": "[resourceGroup().location]" } } } \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-resourcetype.json b/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-resourcetype.json index 71e0c25eac8..5ac446cf6f2 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-resourcetype.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-resourcetype.json @@ -1,28 +1,28 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "properties": { - "compute": { - "kind": "kubernetes", - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "properties": { + "compute": { + "kind": "kubernetes", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + }, + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" - }, - "aws": { - "scope": "/planes/aws/aws/accounts/140313373712/regions/us-west-2" - } - }, - "recipes": { - "Applications.Dapr/pubsub":{ - "cosmos-recipe": { - "templateKind": "bicep", - "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/pubsub" - } + "aws": { + "scope": "/planes/aws/aws/accounts/140313373712/regions/us-west-2" + } + }, + "recipes": { + "Applications.Dapr/pubsub": { + "cosmos-recipe": { + "templateKind": "bicep", + "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/pubsub" } } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-templatekind.json b/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-templatekind.json index b5d0953a0c5..af015a4bc2e 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-templatekind.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresource-invalid-templatekind.json @@ -1,25 +1,25 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "properties": { - "compute": { - "kind": "kubernetes", - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" - }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" - } - }, - "recipes": { - "Applications.Datastores/mongoDatabases":{ - "cosmos-recipe": { - "templateKind": "helm", - "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/mongo" - } + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "properties": { + "compute": { + "kind": "kubernetes", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + }, + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + } + }, + "recipes": { + "Applications.Datastores/mongoDatabases": { + "cosmos-recipe": { + "templateKind": "helm", + "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/mongo" } } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresource-missing-templatekind.json b/pkg/corerp/api/v20231001preview/testdata/environmentresource-missing-templatekind.json index ab8e503830a..b0046cd9025 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresource-missing-templatekind.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresource-missing-templatekind.json @@ -1,24 +1,24 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "properties": { - "compute": { - "kind": "kubernetes", - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" - }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" - } - }, - "recipes": { - "Applications.Datastores/mongoDatabases":{ - "cosmos-recipe": { - "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/mongo" - } + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "properties": { + "compute": { + "kind": "kubernetes", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + }, + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + } + }, + "recipes": { + "Applications.Datastores/mongoDatabases": { + "cosmos-recipe": { + "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/mongo" } } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresource-terraformrecipe-localpath.json b/pkg/corerp/api/v20231001preview/testdata/environmentresource-terraformrecipe-localpath.json index 145cf4a3c59..24a92d514c4 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresource-terraformrecipe-localpath.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresource-terraformrecipe-localpath.json @@ -1,25 +1,25 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "properties": { - "compute": { - "kind": "kubernetes", - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" - }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" - } - }, - "recipes": { - "Applications.Datastores/mongoDatabases":{ - "cosmos-recipe": { - "templateKind": "terraform", - "templatePath": "../not-allowed/" - } + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "properties": { + "compute": { + "kind": "kubernetes", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + }, + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + } + }, + "recipes": { + "Applications.Datastores/mongoDatabases": { + "cosmos-recipe": { + "templateKind": "terraform", + "templatePath": "../not-allowed/" } } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresource-with-workload-identity.json b/pkg/corerp/api/v20231001preview/testdata/environmentresource-with-workload-identity.json index 11ce3dc424b..314b587aed9 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresource-with-workload-identity.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresource-with-workload-identity.json @@ -20,13 +20,16 @@ }, "recipeConfig": { "terraform": { - "authentication": { - "git": {} - } + "authentication": { + "git": { + "pat": {} + } + }, + "providers": {} } }, "recipes": { - "Applications.Datastores/mongoDatabases":{ + "Applications.Datastores/mongoDatabases": { "cosmos-recipe": { "templateKind": "bicep", "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresource.json b/pkg/corerp/api/v20231001preview/testdata/environmentresource.json index e89fe6d6c76..9ad9362f5ad 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresource.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresource.json @@ -21,45 +21,75 @@ "authentication": { "git": { "pat": { - "dev.azure.com":{ - "secret":"/planes/radius/local/resourcegroups/default/providers/Applications.Core/secretStores/github" + "dev.azure.com": { + "secret": "/planes/radius/local/resourcegroups/default/providers/Applications.Core/secretStores/github" } } } + }, + "providers": { + "azurerm": [ + { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "secrets": { + "my_secret_1": { + "source": "source.my_secret_1", + "key": "secret.one" + }, + "my_secret_2": { + "source": "source.my_secret_2", + "key": "secret.two" + } + } + } + ] + } + }, + "envVariables": { + "myEnvVar": "myEnvValue", + "secrets": { + "my_secret_1": { + "source": "source.my_secret_1", + "key": "secret.one" + }, + "my_secret_2": { + "source": "source.my_secret_2", + "key": "secret.two" + } } } }, "recipes": { - "Applications.Datastores/mongoDatabases":{ + "Applications.Datastores/mongoDatabases": { "cosmos-recipe": { "templateKind": "bicep", "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/mongodatabases", - "parameters":{ + "parameters": { "throughput": 400 } }, "terraform-recipe": { "templateKind": "terraform", "templatePath": "Azure/cosmosdb/azurerm", - "templateVersion":"1.1.0" + "templateVersion": "1.1.0" }, - "terraform-without-version":{ + "terraform-without-version": { "templateKind": "terraform", "templatePath": "http://example.com/myrecipe.zip" } }, - "Applications.Datastores/redisCaches":{ + "Applications.Datastores/redisCaches": { "redis-recipe": { "templateKind": "bicep", "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/rediscaches", "plainHttp": true } }, - "Applications.Dapr/stateStores":{ + "Applications.Dapr/stateStores": { "statestore-recipe": { "templateKind": "terraform", "templatePath": "Azure/storage/azurerm", - "templateVersion":"1.1.0" + "templateVersion": "1.1.0" } } }, diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel-with-workload-identity.json b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel-with-workload-identity.json index c66221ed4b5..3c2be287e57 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel-with-workload-identity.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel-with-workload-identity.json @@ -33,13 +33,13 @@ }, "recipeConfig": { "terraform": { - "authentication": { - "git": {} - } + "authentication": { + "git": {} + } } - }, + }, "recipes": { - "Applications.Datastores/mongoDatabases":{ + "Applications.Datastores/mongoDatabases": { "cosmos-recipe": { "templateKind": "bicep", "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel.json b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel.json index fb126cef61b..99c93929515 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodel.json @@ -34,28 +34,58 @@ "authentication": { "git": { "pat": { - "dev.azure.com":{ - "secret":"/planes/radius/local/resourcegroups/default/providers/Applications.Core/secretStores/github" + "dev.azure.com": { + "secret": "/planes/radius/local/resourcegroups/default/providers/Applications.Core/secretStores/github" } } } + }, + "providers": { + "azurerm": [ + { + "additionalProperties": { + "subscriptionId": "00000000-0000-0000-0000-000000000000" + }, + "secrets": { + "my_secret_1": { + "source": "source.my_secret_1", + "key": "secret.one" + } + } + } + ] + } + }, + "envVariables": { + "additionalProperties": { + "myEnvVar": "myEnvValue" + }, + "secrets": { + "my_secret_1": { + "source": "source.my_secret_1", + "key": "secret.one" + }, + "my_secret_2": { + "source": "source.my_secret_2", + "key": "secret.two" + } } } }, "recipes": { - "Applications.Datastores/mongoDatabases":{ + "Applications.Datastores/mongoDatabases": { "cosmos-recipe": { "templateKind": "bicep", "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb", - "parameters" : { + "parameters": { "throughput": 400 }, - "plainHttp":true + "plainHttp": true }, "terraform-recipe": { "templateKind": "terraform", "templatePath": "Azure/cosmosdb/azurerm", - "templateVersion":"1.1.0" + "templateVersion": "1.1.0" } } }, diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptyext.json b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptyext.json index 13fc6e48a64..ff17a6d48b5 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptyext.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptyext.json @@ -1,53 +1,53 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "systemData": { - "createdBy": "fakeid@live.com", - "createdByType": "User", - "createdAt": "2021-09-24T19:09:54.2403864Z", - "lastModifiedBy": "fakeid@live.com", - "lastModifiedByType": "User", - "lastModifiedAt": "2021-09-24T20:09:54.2403864Z" + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "systemData": { + "createdBy": "fakeid@live.com", + "createdByType": "User", + "createdAt": "2021-09-24T19:09:54.2403864Z", + "lastModifiedBy": "fakeid@live.com", + "lastModifiedByType": "User", + "lastModifiedAt": "2021-09-24T20:09:54.2403864Z" + }, + "tags": { + "env": "dev" + }, + "properties": { + "compute": { + "kind": "kubernetes", + "kubernetes": { + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + } }, - "tags": { - "env": "dev" - }, - "properties": { - "compute": { - "kind": "kubernetes", - "kubernetes": { - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" - } - }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" - }, - "aws": { - "scope": "/planes/aws/aws/accounts/140313373712/regions/us-west-2" - } + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" }, - "recipes": { - "Applications.Datastores/mongoDatabases":{ - "cosmos-recipe": { - "templateKind": "bicep", - "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb", - "parameters" : { - "throughput": 400 - } + "aws": { + "scope": "/planes/aws/aws/accounts/140313373712/regions/us-west-2" + } + }, + "recipes": { + "Applications.Datastores/mongoDatabases": { + "cosmos-recipe": { + "templateKind": "bicep", + "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb", + "parameters": { + "throughput": 400 } } - }, - "extensions": [ - { - "kind": "kubernetesMetadata", - "kubernetesmetadata": { - "annotations": {}, - "labels": {} - } + } + }, + "extensions": [ + { + "kind": "kubernetesMetadata", + "kubernetesmetadata": { + "annotations": {}, + "labels": {} } - ] - } - } \ No newline at end of file + } + ] + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptytemplatekind.json b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptytemplatekind.json index 6df2e9860c7..b7d66994893 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptytemplatekind.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresourcedatamodelemptytemplatekind.json @@ -1,37 +1,37 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "systemData": { - "createdBy": "fakeid@live.com", - "createdByType": "User", - "createdAt": "2021-09-24T19:09:54.2403864Z", - "lastModifiedBy": "fakeid@live.com", - "lastModifiedByType": "User", - "lastModifiedAt": "2021-09-24T20:09:54.2403864Z" + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "systemData": { + "createdBy": "fakeid@live.com", + "createdByType": "User", + "createdAt": "2021-09-24T19:09:54.2403864Z", + "lastModifiedBy": "fakeid@live.com", + "lastModifiedByType": "User", + "lastModifiedAt": "2021-09-24T20:09:54.2403864Z" + }, + "tags": { + "env": "dev" + }, + "properties": { + "compute": { + "kind": "kubernetes", + "kubernetes": { + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + } }, - "tags": { - "env": "dev" + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + } }, - "properties": { - "compute": { - "kind": "kubernetes", - "kubernetes": { - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" - } - }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" - } - }, - "recipes": { - "Applications.Datastores/mongoDatabases":{ - "cosmos-recipe": { - "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" - } + "recipes": { + "Applications.Datastores/mongoDatabases": { + "cosmos-recipe": { + "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" } } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext.json b/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext.json index 9ddd7f53e34..c7c81dc48f1 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext.json @@ -1,32 +1,32 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "properties": { - "compute": { - "kind": "kubernetes", - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" - }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "properties": { + "compute": { + "kind": "kubernetes", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + }, + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + } + }, + "recipes": { + "Applications.Datastores/mongoDatabases": { + "cosmos-recipe": { + "templateKind": "bicep", + "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" } - }, - "recipes": { - "Applications.Datastores/mongoDatabases":{ - "cosmos-recipe": { - "templateKind": "bicep", - "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" - } - } - }, - "extensions": [ - { - "kind": "kubernetesMetadata", - "annotations": {}, - "labels": {} - } - ] - } - } \ No newline at end of file + } + }, + "extensions": [ + { + "kind": "kubernetesMetadata", + "annotations": {}, + "labels": {} + } + ] + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext2.json b/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext2.json index 924edce3620..78e4a67ea91 100644 --- a/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext2.json +++ b/pkg/corerp/api/v20231001preview/testdata/environmentresourceemptyext2.json @@ -1,30 +1,30 @@ { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "name": "env0", - "type": "Applications.Core/environments", - "properties": { - "compute": { - "kind": "kubernetes", - "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", - "namespace": "default" - }, - "providers": { - "azure": { - "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", + "name": "env0", + "type": "Applications.Core/environments", + "properties": { + "compute": { + "kind": "kubernetes", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.ContainerService/managedClusters/radiusTestCluster", + "namespace": "default" + }, + "providers": { + "azure": { + "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup" + } + }, + "recipes": { + "Applications.Datastores/mongoDatabases": { + "cosmos-recipe": { + "templateKind": "bicep", + "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" } - }, - "recipes": { - "Applications.Datastores/mongoDatabases":{ - "cosmos-recipe": { - "templateKind": "bicep", - "templatePath": "br:ghcr.io/sampleregistry/radius/recipes/cosmosdb" - } - } - }, - "extensions": [ - { - "kind": "kubernetesMetadata" - } - ] - } - } \ No newline at end of file + } + }, + "extensions": [ + { + "kind": "kubernetesMetadata" + } + ] + } +} \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/extender_manual_nosecrets.json b/pkg/corerp/api/v20231001preview/testdata/extender_manual_nosecrets.json index b862fc5a856..65f737fce9e 100644 --- a/pkg/corerp/api/v20231001preview/testdata/extender_manual_nosecrets.json +++ b/pkg/corerp/api/v20231001preview/testdata/extender_manual_nosecrets.json @@ -5,7 +5,7 @@ "properties": { "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "fromNumber": "222-222-2222", - "resourceProvisioning": "manual" + "fromNumber": "222-222-2222", + "resourceProvisioning": "manual" } } \ No newline at end of file diff --git a/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_manual_nosecrets.json b/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_manual_nosecrets.json index 171e0394bd2..438a7fe8e7a 100644 --- a/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_manual_nosecrets.json +++ b/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_manual_nosecrets.json @@ -16,9 +16,9 @@ "properties": { "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", - "additionalProperties":{ + "additionalProperties": { "fromNumber": "222-222-2222" }, - "resourceProvisioning": "manual" + "resourceProvisioning": "manual" } -} +} \ 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 1a351d8ce56..ffeb32616b7 100644 --- a/pkg/corerp/api/v20231001preview/zz_generated_models.go +++ b/pkg/corerp/api/v20231001preview/zz_generated_models.go @@ -179,7 +179,7 @@ type BicepRecipeProperties struct { // REQUIRED; Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported. TemplatePath *string - // Key/value parameters to pass to the recipe template at deployment + // Key/value parameters to pass to the recipe template at deployment. Parameters map[string]any // Connect to the Bicep registry using HTTP (not-HTTPS). This should be used when the registry is known not to support HTTPS, @@ -201,7 +201,7 @@ type BicepRecipePropertiesUpdate struct { // REQUIRED; Discriminator property for RecipeProperties. TemplateKind *string - // Key/value parameters to pass to the recipe template at deployment + // Key/value parameters to pass to the recipe template at deployment. Parameters map[string]any // Connect to the Bicep registry using HTTP (not-HTTPS). This should be used when the registry is known not to support HTTPS, @@ -626,6 +626,15 @@ type EnvironmentResourceUpdateProperties struct { Simulated *bool } +// EnvironmentVariables describes structure enabling environment variables to be set. +type EnvironmentVariables struct { + // OPTIONAL; Contains additional key/value pairs not defined in the schema. + AdditionalProperties map[string]any + + // The provider secrets passed as environment variables. + Secrets map[string]*RecipeSecret +} + // EphemeralVolume - Specifies an ephemeral volume for a container type EphemeralVolume struct { // REQUIRED; Discriminator property for Volume. @@ -1335,45 +1344,54 @@ func (p *PersistentVolume) GetVolume() *Volume { } } -// Providers - The Cloud providers configuration +// ProviderConfigProperties specifies provider configuration details needed for recipes. +type ProviderConfigProperties struct { + // OPTIONAL; Contains additional key/value pairs not defined in the schema. + AdditionalProperties map[string]any + + // The secrets for the referenced provider resource. + Secrets map[string]*RecipeSecret +} + +// Providers - The Cloud providers configuration. type Providers struct { - // The AWS cloud provider configuration + // The AWS cloud provider configuration. Aws *ProvidersAws - // The Azure cloud provider configuration + // The Azure cloud provider configuration. Azure *ProvidersAzure } -// ProvidersAws - The AWS cloud provider definition +// ProvidersAws - The AWS cloud provider definition. type ProvidersAws struct { - // REQUIRED; Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2' + // REQUIRED; Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'. Scope *string } -// ProvidersAwsUpdate - The AWS cloud provider definition +// ProvidersAwsUpdate - The AWS cloud provider definition. type ProvidersAwsUpdate struct { - // Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2' + // Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'. Scope *string } -// ProvidersAzure - The Azure cloud provider definition +// ProvidersAzure - The Azure cloud provider definition. type ProvidersAzure struct { - // REQUIRED; Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup' + // REQUIRED; Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'. Scope *string } -// ProvidersAzureUpdate - The Azure cloud provider definition +// ProvidersAzureUpdate - The Azure cloud provider definition. type ProvidersAzureUpdate struct { - // Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup' + // Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'. Scope *string } -// ProvidersUpdate - The Cloud providers configuration +// ProvidersUpdate - The Cloud providers configuration. type ProvidersUpdate struct { - // The AWS cloud provider configuration + // The AWS cloud provider configuration. Aws *ProvidersAwsUpdate - // The Azure cloud provider configuration + // The Azure cloud provider configuration. Azure *ProvidersAzureUpdate } @@ -1388,16 +1406,19 @@ type Recipe struct { // RecipeConfigProperties - Configuration for Recipes. Defines how each type of Recipe should be configured and run. type RecipeConfigProperties struct { + // Specifies the environment variables needed for the recipes. + EnvVariables *EnvironmentVariables + // Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as part of Recipe deployment. Terraform *TerraformConfigProperties } // RecipeGetMetadata - Represents the request body of the getmetadata action. type RecipeGetMetadata struct { - // REQUIRED; The name of the recipe registered to the environment + // REQUIRED; The name of the recipe registered to the environment. Name *string - // REQUIRED; Type of the resource this recipe can be consumed by. For example: 'Applications.Datastores/mongoDatabases' + // REQUIRED; Type of the resource this recipe can be consumed by. For example: 'Applications.Datastores/mongoDatabases'. ResourceType *string } @@ -1429,7 +1450,7 @@ type RecipeProperties struct { // REQUIRED; Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported. TemplatePath *string - // Key/value parameters to pass to the recipe template at deployment + // Key/value parameters to pass to the recipe template at deployment. Parameters map[string]any } @@ -1441,7 +1462,7 @@ type RecipePropertiesUpdate struct { // REQUIRED; Discriminator property for RecipeProperties. TemplateKind *string - // Key/value parameters to pass to the recipe template at deployment + // Key/value parameters to pass to the recipe template at deployment. Parameters map[string]any // Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported. @@ -1451,6 +1472,15 @@ type RecipePropertiesUpdate struct { // GetRecipePropertiesUpdate implements the RecipePropertiesUpdateClassification interface for type RecipePropertiesUpdate. func (r *RecipePropertiesUpdate) GetRecipePropertiesUpdate() *RecipePropertiesUpdate { return r } +// RecipeSecret - Specifies the secret details for the provider. +type RecipeSecret struct { + // REQUIRED; The key for the secret in the secret store. + Key *string + + // REQUIRED; The resource id for the secret store containing credentials. + Source *string +} + // RecipeStatus - Recipe status at deployment time for a resource. type RecipeStatus struct { // REQUIRED; TemplateKind is the kind of the recipe template used by the portable resource upon deployment. @@ -1697,6 +1727,9 @@ func (t *TCPHealthProbeProperties) GetHealthProbeProperties() *HealthProbeProper type TerraformConfigProperties struct { // Authentication information used to access private Terraform module sources. Supported module sources: Git. Authentication *AuthConfig + + // Specifies the details of Terraform providers. + Providers map[string][]*ProviderConfigProperties } // TerraformRecipeProperties - Represents Terraform recipe properties. @@ -1707,7 +1740,7 @@ type TerraformRecipeProperties struct { // REQUIRED; Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported. TemplatePath *string - // Key/value parameters to pass to the recipe template at deployment + // Key/value parameters to pass to the recipe template at deployment. Parameters map[string]any // Version of the template to deploy. For Terraform recipes using a module registry this is required, but must be omitted @@ -1729,7 +1762,7 @@ type TerraformRecipePropertiesUpdate struct { // REQUIRED; Discriminator property for RecipeProperties. TemplateKind *string - // Key/value parameters to pass to the recipe template at deployment + // Key/value parameters to pass to the recipe template at deployment. Parameters map[string]any // Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported. diff --git a/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go b/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go index 3af78883083..b04dc29198f 100644 --- a/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go +++ b/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go @@ -1423,6 +1423,48 @@ func (e *EnvironmentResourceUpdateProperties) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type EnvironmentVariables. +func (e EnvironmentVariables) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "secrets", e.Secrets) + if e.AdditionalProperties != nil { + for key, val := range e.AdditionalProperties { + objectMap[key] = val + } + } + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type EnvironmentVariables. +func (e *EnvironmentVariables) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", e, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "secrets": + err = unpopulate(val, "Secrets", &e.Secrets) + delete(rawMsg, key) + default: + if e.AdditionalProperties == nil { + e.AdditionalProperties = map[string]any{} + } + if val != nil { + var aux any + err = json.Unmarshal(val, &aux) + e.AdditionalProperties[key] = aux + } + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", e, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type EphemeralVolume. func (e EphemeralVolume) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -3067,6 +3109,48 @@ func (p *PersistentVolume) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type ProviderConfigProperties. +func (p ProviderConfigProperties) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "secrets", p.Secrets) + if p.AdditionalProperties != nil { + for key, val := range p.AdditionalProperties { + objectMap[key] = val + } + } + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ProviderConfigProperties. +func (p *ProviderConfigProperties) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "secrets": + err = unpopulate(val, "Secrets", &p.Secrets) + delete(rawMsg, key) + default: + if p.AdditionalProperties == nil { + p.AdditionalProperties = map[string]any{} + } + if val != nil { + var aux any + err = json.Unmarshal(val, &aux) + p.AdditionalProperties[key] = aux + } + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type Providers. func (p Providers) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -3271,6 +3355,7 @@ func (r *Recipe) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaller interface for type RecipeConfigProperties. func (r RecipeConfigProperties) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) + populate(objectMap, "envVariables", r.EnvVariables) populate(objectMap, "terraform", r.Terraform) return json.Marshal(objectMap) } @@ -3284,6 +3369,9 @@ func (r *RecipeConfigProperties) UnmarshalJSON(data []byte) error { for key, val := range rawMsg { var err error switch key { + case "envVariables": + err = unpopulate(val, "EnvVariables", &r.EnvVariables) + delete(rawMsg, key) case "terraform": err = unpopulate(val, "Terraform", &r.Terraform) delete(rawMsg, key) @@ -3439,6 +3527,37 @@ func (r *RecipePropertiesUpdate) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type RecipeSecret. +func (r RecipeSecret) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "key", r.Key) + populate(objectMap, "source", r.Source) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RecipeSecret. +func (r *RecipeSecret) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "key": + err = unpopulate(val, "Key", &r.Key) + delete(rawMsg, key) + case "source": + err = unpopulate(val, "Source", &r.Source) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type RecipeStatus. func (r RecipeStatus) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -4070,6 +4189,7 @@ func (t *TCPHealthProbeProperties) UnmarshalJSON(data []byte) error { func (t TerraformConfigProperties) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "authentication", t.Authentication) + populate(objectMap, "providers", t.Providers) return json.Marshal(objectMap) } @@ -4085,6 +4205,9 @@ func (t *TerraformConfigProperties) UnmarshalJSON(data []byte) error { case "authentication": err = unpopulate(val, "Authentication", &t.Authentication) delete(rawMsg, key) + case "providers": + err = unpopulate(val, "Providers", &t.Providers) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", t, err) diff --git a/pkg/corerp/datamodel/recipe_types.go b/pkg/corerp/datamodel/recipe_types.go index 79f8923b5f0..02ba5ca2577 100644 --- a/pkg/corerp/datamodel/recipe_types.go +++ b/pkg/corerp/datamodel/recipe_types.go @@ -20,6 +20,9 @@ package datamodel type RecipeConfigProperties struct { // Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as part of Recipe deployment. Terraform TerraformConfigProperties `json:"terraform,omitempty"` + + // EnvVariables specifies the environment variables to be set for the Recipe execution. + EnvVariables EnvironmentVariables `json:"envVariables,omitempty"` } // TerraformConfigProperties - Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as @@ -27,6 +30,9 @@ type RecipeConfigProperties struct { type TerraformConfigProperties struct { // Authentication information used to access private Terraform module sources. Supported module sources: Git. Authentication AuthConfig `json:"authentication,omitempty"` + + // Providers specifies the Terraform provider configurations. + Providers map[string][]ProviderConfigProperties `json:"providers,omitempty"` } // AuthConfig - Authentication information used to access private Terraform module sources. Supported module sources: Git. @@ -48,3 +54,29 @@ type SecretConfig struct { // 'username' is optional, containing the username associated with the pat. By default no username is specified. Secret string `json:"secret,omitempty"` } + +// EnvironmentVariables represents the environment variables to be set for the recipe execution. +type EnvironmentVariables struct { + // AdditionalProperties represents the additional environment variables to be set for the recipe execution. + AdditionalProperties map[string]any `json:"additionalProperties,omitempty"` + + // Secrets represent the secret values provided for the recipe execution. + Secrets map[string]RecipeSecret `json:"secrets,omitempty"` +} + +// RecipeSecret specifies the secret details for the provider. +type RecipeSecret struct { + // Source represents the resource id for the Application.Core/SecretStore containing credentials. + Source string `json:"source,omitempty"` + + // Key represents the key to the secret in the secret store. + Key string `json:"key"` +} + +type ProviderConfigProperties struct { + // AdditionalProperties represents the additional environment variables to be set for the recipe execution. + AdditionalProperties map[string]any `json:"additionalProperties,omitempty"` + + // Secrets represent the secret values provided for the recipe execution. + Secrets map[string]RecipeSecret `json:"secrets,omitempty"` +} diff --git a/pkg/recipes/controllerconfig/config.go b/pkg/recipes/controllerconfig/config.go index 6ddeb1ef194..e94009728d1 100644 --- a/pkg/recipes/controllerconfig/config.go +++ b/pkg/recipes/controllerconfig/config.go @@ -103,7 +103,7 @@ func New(options hostoptions.HostOptions) (*RecipeControllerConfig, error) { recipes.TemplateKindTerraform: driver.NewTerraformDriver(options.UCPConnection, provider.NewSecretProvider(options.Config.SecretProvider), driver.TerraformOptions{ Path: options.Config.Terraform.Path, - }, cfg.K8sClients.ClientSet), + }, cfg.K8sClients.ClientSet, clientOptions), }, }) diff --git a/pkg/recipes/driver/terraform.go b/pkg/recipes/driver/terraform.go index 1800a2952a1..1841fe4ccd1 100644 --- a/pkg/recipes/driver/terraform.go +++ b/pkg/recipes/driver/terraform.go @@ -25,17 +25,12 @@ import ( "reflect" "strings" - "github.com/google/uuid" v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" "github.com/radius-project/radius/pkg/corerp/api/v20231001preview" - rpv1 "github.com/radius-project/radius/pkg/rp/v1" - "golang.org/x/exp/slices" - "k8s.io/client-go/kubernetes" - "github.com/radius-project/radius/pkg/recipes" - "github.com/radius-project/radius/pkg/recipes/terraform" recipes_util "github.com/radius-project/radius/pkg/recipes/util" + rpv1 "github.com/radius-project/radius/pkg/rp/v1" "github.com/radius-project/radius/pkg/sdk" resources "github.com/radius-project/radius/pkg/ucp/resources" awsresources "github.com/radius-project/radius/pkg/ucp/resources/aws" @@ -44,13 +39,17 @@ import ( "github.com/radius-project/radius/pkg/ucp/ucplog" "github.com/radius-project/radius/pkg/ucp/util" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" + "github.com/google/uuid" tfjson "github.com/hashicorp/terraform-json" + "golang.org/x/exp/slices" + "k8s.io/client-go/kubernetes" ) var _ Driver = (*terraformDriver)(nil) // NewTerraformDriver creates a new instance of driver to execute a Terraform recipe. -func NewTerraformDriver(ucpConn sdk.Connection, secretProvider *ucp_provider.SecretProvider, options TerraformOptions, k8sClientSet kubernetes.Interface) Driver { +func NewTerraformDriver(ucpConn sdk.Connection, secretProvider *ucp_provider.SecretProvider, options TerraformOptions, k8sClientSet kubernetes.Interface, armOptions *arm.ClientOptions) Driver { return &terraformDriver{ terraformExecutor: terraform.NewExecutor(ucpConn, secretProvider, k8sClientSet), options: options, @@ -65,6 +64,9 @@ type TerraformOptions struct { // terraformDriver represents a driver to interact with Terraform Recipe - deploy recipe, delete resources, etc. type terraformDriver struct { + // ArmClientOptions is used to create a new ARM client to interact with Azure resources. + ArmClientOptions *arm.ClientOptions + // terraformExecutor is used to execute Terraform commands - deploy, destroy, etc. terraformExecutor terraform.TerraformExecutor diff --git a/pkg/recipes/driver/terraform_test.go b/pkg/recipes/driver/terraform_test.go index 3e42acdcb8d..3e595c9ff1d 100644 --- a/pkg/recipes/driver/terraform_test.go +++ b/pkg/recipes/driver/terraform_test.go @@ -41,7 +41,7 @@ func setup(t *testing.T) (terraform.MockTerraformExecutor, terraformDriver) { ctrl := gomock.NewController(t) tfExecutor := terraform.NewMockTerraformExecutor(ctrl) - driver := terraformDriver{tfExecutor, TerraformOptions{Path: t.TempDir()}} + driver := terraformDriver{nil, tfExecutor, TerraformOptions{Path: t.TempDir()}} return *tfExecutor, driver } diff --git a/pkg/recipes/terraform/execute.go b/pkg/recipes/terraform/execute.go index 248d4fa1c79..6bdc61dbb29 100644 --- a/pkg/recipes/terraform/execute.go +++ b/pkg/recipes/terraform/execute.go @@ -22,9 +22,6 @@ import ( "fmt" "time" - install "github.com/hashicorp/hc-install" - "github.com/hashicorp/terraform-exec/tfexec" - tfjson "github.com/hashicorp/terraform-json" "github.com/radius-project/radius/pkg/metrics" "github.com/radius-project/radius/pkg/recipes" "github.com/radius-project/radius/pkg/recipes/recipecontext" @@ -35,6 +32,11 @@ import ( "github.com/radius-project/radius/pkg/sdk" ucp_provider "github.com/radius-project/radius/pkg/ucp/secret/provider" "github.com/radius-project/radius/pkg/ucp/ucplog" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" + install "github.com/hashicorp/hc-install" + "github.com/hashicorp/terraform-exec/tfexec" + tfjson "github.com/hashicorp/terraform-json" "go.opentelemetry.io/otel/attribute" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -61,6 +63,9 @@ type executor struct { // k8sClientSet is the Kubernetes client. k8sClientSet kubernetes.Interface + + // armOptions is the options for the Azure Resource Manager client. + armOptions *arm.ClientOptions } // Deploy installs Terraform, creates a working directory, generates a config, and runs Terraform init and @@ -179,7 +184,7 @@ func (e *executor) GetRecipeMetadata(ctx context.Context, options Options) (map[ return nil, err } - _, err = getTerraformConfig(ctx, tf.WorkingDir(), options) + _, err = getTerraformConfig(ctx, tf.WorkingDir(), options, e.armOptions) if err != nil { return nil, err } @@ -199,7 +204,7 @@ func (e *executor) generateConfig(ctx context.Context, tf *tfexec.Terraform, opt logger := ucplog.FromContextOrDiscard(ctx) workingDir := tf.WorkingDir() - tfConfig, err := getTerraformConfig(ctx, workingDir, options) + tfConfig, err := getTerraformConfig(ctx, workingDir, options, e.armOptions) if err != nil { return "", err } @@ -291,7 +296,7 @@ func downloadAndInspect(ctx context.Context, tf *tfexec.Terraform, options Optio } // getTerraformConfig initializes the Terraform json config with provided module source and saves it -func getTerraformConfig(ctx context.Context, workingDir string, options Options) (*config.TerraformConfig, error) { +func getTerraformConfig(ctx context.Context, workingDir string, options Options, armOptions *arm.ClientOptions) (*config.TerraformConfig, error) { // Generate Terraform json config in the working directory // Use recipe name as a local reference to the module. // Modules are downloaded in a subdirectory in the working directory. Name of the module specified in the diff --git a/pkg/recipes/terraform/execute_test.go b/pkg/recipes/terraform/execute_test.go index 87e54e8e37c..4e953ecea87 100644 --- a/pkg/recipes/terraform/execute_test.go +++ b/pkg/recipes/terraform/execute_test.go @@ -78,7 +78,7 @@ func Test_GetTerraformConfig(t *testing.T) { Module: map[string]config.TFModuleConfig{ "test-recipe": {"source": "test/module/source"}}, } - tfConfig, err := getTerraformConfig(testcontext.New(t), testDir, options) + tfConfig, err := getTerraformConfig(testcontext.New(t), testDir, options, nil) require.NoError(t, err) require.Equal(t, &expectedConfig, tfConfig) } @@ -95,7 +95,7 @@ func Test_GetTerraformConfig_EmptyRecipeName(t *testing.T) { ResourceRecipe: &recipes.ResourceMetadata{}, } - _, err := getTerraformConfig(testcontext.New(t), testDir, options) + _, err := getTerraformConfig(testcontext.New(t), testDir, options, nil) require.Error(t, err) require.Equal(t, err, ErrRecipeNameEmpty) } @@ -110,7 +110,7 @@ func Test_GetTerraformConfig_InvalidDirectory(t *testing.T) { ResourceRecipe: &recipes.ResourceMetadata{}, } - _, err := getTerraformConfig(testcontext.New(t), workingDir, options) + _, err := getTerraformConfig(testcontext.New(t), workingDir, options, nil) require.Error(t, err) require.Contains(t, err.Error(), "error creating file: open invalid-directory/main.tf.json: no such file or directory") } 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 a884c7b418f..e4b47d9aa91 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 @@ -3620,6 +3620,26 @@ } } }, + "EnvironmentVariables": { + "type": "object", + "description": "EnvironmentVariables describes structure enabling environment variables to be set.", + "properties": { + "secrets": { + "type": "object", + "description": "The provider secrets passed as environment variables.", + "additionalProperties": { + "$ref": "#/definitions/RecipeSecret" + } + } + }, + "additionalProperties": true, + "allOf": [ + { + "type": "object", + "additionalProperties": true + } + ] + }, "EphemeralVolume": { "type": "object", "description": "Specifies an ephemeral volume for a container", @@ -4601,27 +4621,47 @@ ] } }, + "ProviderConfigProperties": { + "type": "object", + "description": "ProviderConfigProperties specifies provider configuration details needed for recipes.", + "properties": { + "secrets": { + "type": "object", + "description": "The secrets for the referenced provider resource.", + "additionalProperties": { + "$ref": "#/definitions/RecipeSecret" + } + } + }, + "additionalProperties": true, + "allOf": [ + { + "type": "object", + "additionalProperties": true + } + ] + }, "Providers": { "type": "object", - "description": "The Cloud providers configuration", + "description": "The Cloud providers configuration.", "properties": { "azure": { "$ref": "#/definitions/ProvidersAzure", - "description": "The Azure cloud provider configuration" + "description": "The Azure cloud provider configuration." }, "aws": { "$ref": "#/definitions/ProvidersAws", - "description": "The AWS cloud provider configuration" + "description": "The AWS cloud provider configuration." } } }, "ProvidersAws": { "type": "object", - "description": "The AWS cloud provider definition", + "description": "The AWS cloud provider definition.", "properties": { "scope": { "type": "string", - "description": "Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'" + "description": "Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'." } }, "required": [ @@ -4630,21 +4670,21 @@ }, "ProvidersAwsUpdate": { "type": "object", - "description": "The AWS cloud provider definition", + "description": "The AWS cloud provider definition.", "properties": { "scope": { "type": "string", - "description": "Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'" + "description": "Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'." } } }, "ProvidersAzure": { "type": "object", - "description": "The Azure cloud provider definition", + "description": "The Azure cloud provider definition.", "properties": { "scope": { "type": "string", - "description": "Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'" + "description": "Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'." } }, "required": [ @@ -4653,25 +4693,25 @@ }, "ProvidersAzureUpdate": { "type": "object", - "description": "The Azure cloud provider definition", + "description": "The Azure cloud provider definition.", "properties": { "scope": { "type": "string", - "description": "Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'" + "description": "Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'." } } }, "ProvidersUpdate": { "type": "object", - "description": "The Cloud providers configuration", + "description": "The Cloud providers configuration.", "properties": { "azure": { "$ref": "#/definitions/ProvidersAzureUpdate", - "description": "The Azure cloud provider configuration" + "description": "The Azure cloud provider configuration." }, "aws": { "$ref": "#/definitions/ProvidersAwsUpdate", - "description": "The AWS cloud provider configuration" + "description": "The AWS cloud provider configuration." } } }, @@ -4755,6 +4795,10 @@ "terraform": { "$ref": "#/definitions/TerraformConfigProperties", "description": "Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as part of Recipe deployment." + }, + "envVariables": { + "$ref": "#/definitions/EnvironmentVariables", + "description": "Specifies the environment variables needed for the recipes." } } }, @@ -4764,11 +4808,11 @@ "properties": { "resourceType": { "type": "string", - "description": "Type of the resource this recipe can be consumed by. For example: 'Applications.Datastores/mongoDatabases'" + "description": "Type of the resource this recipe can be consumed by. For example: 'Applications.Datastores/mongoDatabases'." }, "name": { "type": "string", - "description": "The name of the recipe registered to the environment" + "description": "The name of the recipe registered to the environment." } }, "required": [ @@ -4822,7 +4866,7 @@ }, "parameters": { "type": "object", - "description": "Key/value parameters to pass to the recipe template at deployment", + "description": "Key/value parameters to pass to the recipe template at deployment.", "properties": {} } }, @@ -4846,7 +4890,7 @@ }, "parameters": { "type": "object", - "description": "Key/value parameters to pass to the recipe template at deployment", + "description": "Key/value parameters to pass to the recipe template at deployment.", "properties": {} } }, @@ -4855,6 +4899,24 @@ "templateKind" ] }, + "RecipeSecret": { + "type": "object", + "description": "Specifies the secret details for the provider.", + "properties": { + "source": { + "type": "string", + "description": "The resource id for the secret store containing credentials." + }, + "key": { + "type": "string", + "description": "The key for the secret in the secret store." + } + }, + "required": [ + "source", + "key" + ] + }, "RecipeStatus": { "type": "object", "description": "Recipe status at deployment time for a resource.", @@ -5279,6 +5341,17 @@ "authentication": { "$ref": "#/definitions/AuthConfig", "description": "Authentication information used to access private Terraform module sources. Supported module sources: Git." + }, + "providers": { + "type": "object", + "description": "Specifies the details of Terraform providers.", + "additionalProperties": { + "items": { + "$ref": "#/definitions/ProviderConfigProperties" + }, + "type": "array", + "x-ms-identifiers": [] + } } } }, diff --git a/typespec/Applications.Core/containers.tsp b/typespec/Applications.Core/containers.tsp index 66b060abed8..e33753fd974 100644 --- a/typespec/Applications.Core/containers.tsp +++ b/typespec/Applications.Core/containers.tsp @@ -38,7 +38,8 @@ using OpenAPI; namespace Applications.Core; -model ContainerResource is TrackedResourceRequired{ +model ContainerResource + is TrackedResourceRequired { @doc("Container name") @path @key("containerName") diff --git a/typespec/Applications.Core/environments.tsp b/typespec/Applications.Core/environments.tsp index 9bb025b9bc6..c655f358193 100644 --- a/typespec/Applications.Core/environments.tsp +++ b/typespec/Applications.Core/environments.tsp @@ -39,7 +39,8 @@ using OpenAPI; namespace Applications.Core; @doc("The environment resource") -model EnvironmentResource is TrackedResourceRequired{ +model EnvironmentResource + is TrackedResourceRequired { @doc("environment name") @key("environmentName") @path @@ -77,23 +78,29 @@ model EnvironmentProperties { model RecipeConfigProperties { @doc("Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as part of Recipe deployment.") terraform?: TerraformConfigProperties; + + @doc("Specifies the environment variables needed for the recipes.") + envVariables?: EnvironmentVariables; } @doc("Configuration for Terraform Recipes. Controls how Terraform plans and applies templates as part of Recipe deployment.") -model TerraformConfigProperties{ - @doc("Authentication information used to access private Terraform module sources. Supported module sources: Git.") +model TerraformConfigProperties { + @doc("Authentication information used to access private Terraform module sources. Supported module sources: Git.") authentication?: AuthConfig; + + @doc("Specifies the details of Terraform providers.") + providers?: Record>; } @doc("Authentication information used to access private Terraform module sources. Supported module sources: Git.") -model AuthConfig{ +model AuthConfig { @doc("Authentication information used to access private Terraform modules from Git repository sources.") git?: GitAuthConfig; } @doc("Authentication information used to access private Terraform modules from Git repository sources.") -model GitAuthConfig{ - @doc("Personal Access Token (PAT) configuration used to authenticate to Git platforms.") +model GitAuthConfig { + @doc("Personal Access Token (PAT) configuration used to authenticate to Git platforms.") pat?: Record; } @@ -103,24 +110,47 @@ model SecretConfig { secret?: string; } -@doc("The Cloud providers configuration") +#suppress "@azure-tools/typespec-azure-core/bad-record-type" +@doc("ProviderConfigProperties specifies provider configuration details needed for recipes.") +model ProviderConfigProperties extends Record { + @doc("The secrets for the referenced provider resource.") + secrets?: Record; +} + +#suppress "@azure-tools/typespec-azure-core/bad-record-type" +@doc("EnvironmentVariables describes structure enabling environment variables to be set.") +model EnvironmentVariables extends Record { + @doc("The provider secrets passed as environment variables.") + secrets?: Record; +} + +@doc("Specifies the secret details for the provider.") +model RecipeSecret { + @doc("The resource id for the secret store containing credentials.") + source: string; + + @doc("The key for the secret in the secret store.") + key: string; +} + +@doc("The Cloud providers configuration.") model Providers { - @doc("The Azure cloud provider configuration") + @doc("The Azure cloud provider configuration.") azure?: ProvidersAzure; - @doc("The AWS cloud provider configuration") + @doc("The AWS cloud provider configuration.") aws?: ProvidersAws; } -@doc("The Azure cloud provider definition") +@doc("The Azure cloud provider definition.") model ProvidersAzure { - @doc("Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'") + @doc("Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'.") scope: string; } -@doc("The AWS cloud provider definition") +@doc("The AWS cloud provider definition.") model ProvidersAws { - @doc("Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'") + @doc("Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'.") scope: string; } @@ -130,7 +160,7 @@ model RecipeProperties { @doc("Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported.") templatePath: string; - @doc("Key/value parameters to pass to the recipe template at deployment") + @doc("Key/value parameters to pass to the recipe template at deployment.") parameters?: {}; } @@ -154,10 +184,10 @@ model TerraformRecipeProperties extends RecipeProperties { @doc("Represents the request body of the getmetadata action.") model RecipeGetMetadata { - @doc("Type of the resource this recipe can be consumed by. For example: 'Applications.Datastores/mongoDatabases'") + @doc("Type of the resource this recipe can be consumed by. For example: 'Applications.Datastores/mongoDatabases'.") resourceType: string; - @doc("The name of the recipe registered to the environment") + @doc("The name of the recipe registered to the environment.") name: string; } diff --git a/typespec/Applications.Core/extenders.tsp b/typespec/Applications.Core/extenders.tsp index 2a104c2eb7d..ec0f056d8c6 100644 --- a/typespec/Applications.Core/extenders.tsp +++ b/typespec/Applications.Core/extenders.tsp @@ -40,7 +40,8 @@ namespace Applications.Core; model ExtenderListSecretResponse {} @doc("ExtenderResource portable resource") -model ExtenderResource is TrackedResourceRequired{ +model ExtenderResource + is TrackedResourceRequired { @path @doc("The name of the ExtenderResource portable resource") @key("extenderName")