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 ef2b587d56..18fdd4b5b3 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":0,"Description":"Application properties"},"tags":{"Type":45,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"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 portable resource at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the portable resource 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"},"outputResources":{"Type":44,"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":"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":43}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":51,"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":56,"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":[47,48,49,50]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[52,53,54,55]}},{"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":58,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":59,"Flags":10,"Description":"The resource api version"},"properties":{"Type":61,"Flags":0,"Description":"Container properties"},"tags":{"Type":121,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"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 portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":69,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"container":{"Type":70,"Flags":1,"Description":"Definition of a container"},"connections":{"Type":107,"Flags":0,"Description":"Specifies a connection to another resource."},"identity":{"Type":37,"Flags":0,"Description":"IdentitySettings is the external identity setting."},"extensions":{"Type":108,"Flags":0,"Description":"Extensions spec of the resource"},"resourceProvisioning":{"Type":111,"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":113,"Flags":0,"Description":"A collection of references to resources associated with the container"},"restartPolicy":{"Type":117,"Flags":0,"Description":"Restart policy for the container"},"runtimes":{"Type":118,"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":[62,63,64,65,66,67,68]}},{"2":{"Name":"Container","Properties":{"image":{"Type":4,"Flags":1,"Description":"The registry and image to download and run in your container"},"imagePullPolicy":{"Type":74,"Flags":0,"Description":"The image pull policy for the container"},"env":{"Type":75,"Flags":0,"Description":"environment"},"ports":{"Type":80,"Flags":0,"Description":"container ports"},"readinessProbe":{"Type":81,"Flags":0,"Description":"Properties for readiness/liveness probe"},"livenessProbe":{"Type":81,"Flags":0,"Description":"Properties for readiness/liveness probe"},"volumes":{"Type":100,"Flags":0,"Description":"container volumes"},"command":{"Type":101,"Flags":0,"Description":"Entrypoint array. Overrides the container image's ENTRYPOINT"},"args":{"Type":102,"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":[71,72,73]}},{"2":{"Name":"ContainerEnv","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"ContainerPortProperties","Properties":{"containerPort":{"Type":3,"Flags":1,"Description":"The listening port number"},"protocol":{"Type":79,"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":[77,78]}},{"2":{"Name":"ContainerPorts","Properties":{},"AdditionalProperties":76}},{"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":82,"httpGet":84,"tcp":87}}},{"2":{"Name":"ExecHealthProbeProperties","Properties":{"command":{"Type":4,"Flags":1,"Description":"Command to execute to probe readiness/liveness"},"kind":{"Type":83,"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":85,"Flags":0,"Description":"Custom HTTP headers to add to the get request"},"kind":{"Type":86,"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":88,"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":90,"persistent":95}}},{"2":{"Name":"EphemeralVolume","Properties":{"managedStore":{"Type":93,"Flags":1,"Description":"The managed store for the ephemeral volume"},"kind":{"Type":94,"Flags":1,"Description":"Discriminator property for Volume."}}}},{"6":{"Value":"memory"}},{"6":{"Value":"disk"}},{"5":{"Elements":[91,92]}},{"6":{"Value":"ephemeral"}},{"2":{"Name":"PersistentVolume","Properties":{"permission":{"Type":98,"Flags":0,"Description":"The persistent volume permission"},"source":{"Type":4,"Flags":1,"Description":"The source of the volume"},"kind":{"Type":99,"Flags":1,"Description":"Discriminator property for Volume."}}}},{"6":{"Value":"read"}},{"6":{"Value":"write"}},{"5":{"Elements":[96,97]}},{"6":{"Value":"persistent"}},{"2":{"Name":"ContainerVolumes","Properties":{},"AdditionalProperties":89}},{"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":104,"Flags":0,"Description":"IAM properties"}}}},{"2":{"Name":"IamProperties","Properties":{"kind":{"Type":105,"Flags":1,"Description":"The kind of IAM provider to configure"},"roles":{"Type":106,"Flags":0,"Description":"RBAC permissions to be assigned on the source resource"}}}},{"6":{"Value":"azure"}},{"3":{"ItemType":4}},{"2":{"Name":"ContainerPropertiesConnections","Properties":{},"AdditionalProperties":103}},{"3":{"ItemType":20}},{"6":{"Value":"internal"}},{"6":{"Value":"manual"}},{"5":{"Elements":[109,110]}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":112}},{"6":{"Value":"Always"}},{"6":{"Value":"OnFailure"}},{"6":{"Value":"Never"}},{"5":{"Elements":[114,115,116]}},{"2":{"Name":"RuntimesProperties","Properties":{"kubernetes":{"Type":119,"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":120,"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":60}},{"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":123,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":124,"Flags":10,"Description":"The resource api version"},"properties":{"Type":126,"Flags":0,"Description":"Environment properties"},"tags":{"Type":146,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"EnvironmentProperties","Properties":{"provisioningState":{"Type":134,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"compute":{"Type":36,"Flags":1,"Description":"Represents backing compute resource"},"providers":{"Type":135,"Flags":0,"Description":"The Cloud providers configuration"},"simulated":{"Type":2,"Flags":0,"Description":"Simulated environment."},"recipes":{"Type":144,"Flags":0,"Description":"Specifies Recipes linked to the Environment."},"extensions":{"Type":145,"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":[127,128,129,130,131,132,133]}},{"2":{"Name":"Providers","Properties":{"azure":{"Type":136,"Flags":0,"Description":"The Azure cloud provider definition"},"aws":{"Type":137,"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":139,"terraform":141}}},{"2":{"Name":"BicepRecipeProperties","Properties":{"templateKind":{"Type":140,"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":142,"Flags":1,"Description":"Discriminator property for RecipeProperties."}}}},{"6":{"Value":"terraform"}},{"2":{"Name":"DictionaryOfRecipeProperties","Properties":{},"AdditionalProperties":138}},{"2":{"Name":"EnvironmentPropertiesRecipes","Properties":{},"AdditionalProperties":143}},{"3":{"ItemType":20}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/environments@2023-10-01-preview","ScopeType":0,"Body":125}},{"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":148,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":149,"Flags":10,"Description":"The resource api version"},"properties":{"Type":151,"Flags":0,"Description":"ExtenderResource portable resource properties"},"tags":{"Type":164,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"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":159,"Flags":2,"Description":"Provisioning state of the portable 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":160,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":163,"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":[152,153,154,155,156,157,158]}},{"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":[161,162]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/extenders@2023-10-01-preview","ScopeType":0,"Body":150}},{"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":166,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":167,"Flags":10,"Description":"The resource api version"},"properties":{"Type":169,"Flags":0,"Description":"Gateway properties"},"tags":{"Type":185,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"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 portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":177,"Flags":2,"Description":"Provisioning state of the portable 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":178,"Flags":0,"Description":"Declare hostname information for the Gateway. Leaving the hostname empty auto-assigns one: mygateway.myapp.PUBLICHOSTNAMEORIP.nip.io."},"routes":{"Type":180,"Flags":1,"Description":"Routes attached to this Gateway"},"tls":{"Type":181,"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":[170,171,172,173,174,175,176]}},{"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":179}},{"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":184,"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":[182,183]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/gateways@2023-10-01-preview","ScopeType":0,"Body":168}},{"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":187,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":188,"Flags":10,"Description":"The resource api version"},"properties":{"Type":190,"Flags":0,"Description":"HTTPRoute properties"},"tags":{"Type":199,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"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 portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":198,"Flags":2,"Description":"Provisioning state of the portable 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":[191,192,193,194,195,196,197]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/httpRoutes@2023-10-01-preview","ScopeType":0,"Body":189}},{"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":201,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":202,"Flags":10,"Description":"The resource api version"},"properties":{"Type":204,"Flags":0,"Description":"The properties of SecretStore"},"tags":{"Type":222,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"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 portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":212,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"type":{"Type":215,"Flags":0,"Description":"The type of SecretStore data"},"data":{"Type":221,"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":[205,206,207,208,209,210,211]}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[213,214]}},{"2":{"Name":"SecretValueProperties","Properties":{"encoding":{"Type":219,"Flags":0,"Description":"The type of SecretValue Encoding"},"value":{"Type":4,"Flags":0,"Description":"The value of secret."},"valueFrom":{"Type":220,"Flags":0,"Description":"The Secret value source properties"}}}},{"6":{"Value":"raw"}},{"6":{"Value":"base64"}},{"5":{"Elements":[217,218]}},{"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":216}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/secretStores@2023-10-01-preview","ScopeType":0,"Body":203}},{"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":224,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":225,"Flags":10,"Description":"The resource api version"},"properties":{"Type":227,"Flags":0,"Description":"Volume properties"},"tags":{"Type":259,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":46,"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 portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":235,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."}},"Elements":{"azure.com.keyvault":236}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[228,229,230,231,232,233,234]}},{"2":{"Name":"AzureKeyVaultVolumeProperties","Properties":{"certificates":{"Type":249,"Flags":0,"Description":"The KeyVault certificates that this volume exposes"},"keys":{"Type":251,"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":257,"Flags":0,"Description":"The KeyVault secrets that this volume exposes"},"kind":{"Type":258,"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":241,"Flags":0,"Description":"Represents secret encodings"},"format":{"Type":244,"Flags":0,"Description":"Represents certificate formats"},"name":{"Type":4,"Flags":1,"Description":"The name of the certificate"},"certType":{"Type":248,"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":[238,239,240]}},{"6":{"Value":"pem"}},{"6":{"Value":"pfx"}},{"5":{"Elements":[242,243]}},{"6":{"Value":"certificate"}},{"6":{"Value":"privatekey"}},{"6":{"Value":"publickey"}},{"5":{"Elements":[245,246,247]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesCertificates","Properties":{},"AdditionalProperties":237}},{"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":250}},{"2":{"Name":"SecretObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":256,"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":[253,254,255]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesSecrets","Properties":{},"AdditionalProperties":252}},{"6":{"Value":"azure.com.keyvault"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/volumes@2023-10-01-preview","ScopeType":0,"Body":226}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/extenders","ApiVersion":"2023-10-01-preview","Output":0,"Input":0}},{"2":{"Name":"SecretStoreListSecretsResult","Properties":{"type":{"Type":265,"Flags":2,"Description":"The type of SecretStore data"},"data":{"Type":266,"Flags":2,"Description":"An object to represent key-value type secrets"}}}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[263,264]}},{"2":{"Name":"SecretStoreListSecretsResultData","Properties":{},"AdditionalProperties":216}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/secretStores","ApiVersion":"2023-10-01-preview","Output":262,"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":0,"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 portable resource at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the portable resource 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":0,"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 portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":70,"Flags":2,"Description":"Provisioning state of the portable 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":0,"Description":"Environment properties"},"tags":{"Type":147,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"EnvironmentProperties","Properties":{"provisioningState":{"Type":135,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"compute":{"Type":36,"Flags":1,"Description":"Represents backing compute resource"},"providers":{"Type":136,"Flags":0,"Description":"The Cloud providers configuration"},"simulated":{"Type":2,"Flags":0,"Description":"Simulated environment."},"recipes":{"Type":145,"Flags":0,"Description":"Specifies Recipes linked to the Environment."},"extensions":{"Type":146,"Flags":0,"Description":"The environment extension."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[128,129,130,131,132,133,134]}},{"2":{"Name":"Providers","Properties":{"azure":{"Type":137,"Flags":0,"Description":"The Azure cloud provider definition"},"aws":{"Type":138,"Flags":0,"Description":"The AWS cloud provider definition"}}}},{"2":{"Name":"ProvidersAzure","Properties":{"scope":{"Type":4,"Flags":1,"Description":"Target scope for Azure resources to be deployed into. For example: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup'"}}}},{"2":{"Name":"ProvidersAws","Properties":{"scope":{"Type":4,"Flags":1,"Description":"Target scope for AWS resources to be deployed into. For example: '/planes/aws/aws/accounts/000000000000/regions/us-west-2'"}}}},{"7":{"Name":"RecipeProperties","Discriminator":"templateKind","BaseProperties":{"templatePath":{"Type":4,"Flags":1,"Description":"Path to the template provided by the recipe. Currently only link to Azure Container Registry is supported."},"parameters":{"Type":0,"Flags":0,"Description":"Any object"}},"Elements":{"bicep":140,"terraform":142}}},{"2":{"Name":"BicepRecipeProperties","Properties":{"templateKind":{"Type":141,"Flags":1,"Description":"Discriminator property for RecipeProperties."}}}},{"6":{"Value":"bicep"}},{"2":{"Name":"TerraformRecipeProperties","Properties":{"templateVersion":{"Type":4,"Flags":0,"Description":"Version of the template to deploy. For Terraform recipes using a module registry this is required, but must be omitted for other module sources."},"templateKind":{"Type":143,"Flags":1,"Description":"Discriminator property for RecipeProperties."}}}},{"6":{"Value":"terraform"}},{"2":{"Name":"DictionaryOfRecipeProperties","Properties":{},"AdditionalProperties":139}},{"2":{"Name":"EnvironmentPropertiesRecipes","Properties":{},"AdditionalProperties":144}},{"3":{"ItemType":20}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/environments@2023-10-01-preview","ScopeType":0,"Body":126}},{"6":{"Value":"Applications.Core/extenders"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/extenders","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":149,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":150,"Flags":10,"Description":"The resource api version"},"properties":{"Type":152,"Flags":0,"Description":"ExtenderResource portable resource properties"},"tags":{"Type":165,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"ExtenderProperties","Properties":{"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the portable resource is linked to"},"application":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by (if applicable)"},"provisioningState":{"Type":160,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":0,"Flags":0,"Description":"Any object"},"recipe":{"Type":161,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":164,"Flags":0,"Description":"Specifies how the underlying service/resource is provisioned and managed. Available values are 'recipe', where Radius manages the lifecycle of the resource through a Recipe, and 'manual', where a user manages the resource and provides the values."}},"AdditionalProperties":0}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[153,154,155,156,157,158,159]}},{"2":{"Name":"Recipe","Properties":{"name":{"Type":4,"Flags":1,"Description":"The name of the recipe within the environment to use"},"parameters":{"Type":0,"Flags":0,"Description":"Any object"}}}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[162,163]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/extenders@2023-10-01-preview","ScopeType":0,"Body":151}},{"6":{"Value":"Applications.Core/gateways"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/gateways","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":167,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":168,"Flags":10,"Description":"The resource api version"},"properties":{"Type":170,"Flags":0,"Description":"Gateway properties"},"tags":{"Type":186,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"GatewayProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":178,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"internal":{"Type":2,"Flags":0,"Description":"Sets Gateway to not be exposed externally (no public IP address associated). Defaults to false (exposed to internet)."},"hostname":{"Type":179,"Flags":0,"Description":"Declare hostname information for the Gateway. Leaving the hostname empty auto-assigns one: mygateway.myapp.PUBLICHOSTNAMEORIP.nip.io."},"routes":{"Type":181,"Flags":1,"Description":"Routes attached to this Gateway"},"tls":{"Type":182,"Flags":0,"Description":"TLS configuration definition for Gateway resource."},"url":{"Type":4,"Flags":2,"Description":"URL of the gateway resource. Readonly"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[171,172,173,174,175,176,177]}},{"2":{"Name":"GatewayHostname","Properties":{"prefix":{"Type":4,"Flags":0,"Description":"Specify a prefix for the hostname: myhostname.myapp.PUBLICHOSTNAMEORIP.nip.io. Mutually exclusive with 'fullyQualifiedHostname' and will be overridden if both are defined."},"fullyQualifiedHostname":{"Type":4,"Flags":0,"Description":"Specify a fully-qualified domain name: myapp.mydomain.com. Mutually exclusive with 'prefix' and will take priority if both are defined."}}}},{"2":{"Name":"GatewayRoute","Properties":{"path":{"Type":4,"Flags":0,"Description":"The path to match the incoming request path on. Ex - /myservice."},"destination":{"Type":4,"Flags":0,"Description":"The HttpRoute to route to. Ex - myserviceroute.id."},"replacePrefix":{"Type":4,"Flags":0,"Description":"Optionally update the prefix when sending the request to the service. Ex - replacePrefix: '/' and path: '/myservice' will transform '/myservice/myroute' to '/myroute'"}}}},{"3":{"ItemType":180}},{"2":{"Name":"GatewayTls","Properties":{"sslPassthrough":{"Type":2,"Flags":0,"Description":"If true, gateway lets the https traffic sslPassthrough to the backend servers for decryption."},"minimumProtocolVersion":{"Type":185,"Flags":0,"Description":"Tls Minimum versions for Gateway resource."},"certificateFrom":{"Type":4,"Flags":0,"Description":"The resource id for the secret containing the TLS certificate and key for the gateway."}}}},{"6":{"Value":"1.2"}},{"6":{"Value":"1.3"}},{"5":{"Elements":[183,184]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/gateways@2023-10-01-preview","ScopeType":0,"Body":169}},{"6":{"Value":"Applications.Core/httpRoutes"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/httpRoutes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":188,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":189,"Flags":10,"Description":"The resource api version"},"properties":{"Type":191,"Flags":0,"Description":"HTTPRoute properties"},"tags":{"Type":200,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"HttpRouteProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":199,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"hostname":{"Type":4,"Flags":0,"Description":"The internal hostname accepting traffic for the HTTP Route. Readonly."},"port":{"Type":3,"Flags":0,"Description":"The port number for the HTTP Route. Defaults to 80. Readonly."},"scheme":{"Type":4,"Flags":2,"Description":"The scheme used for traffic. Readonly."},"url":{"Type":4,"Flags":2,"Description":"A stable URL that that can be used to route traffic to a resource. Readonly."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[192,193,194,195,196,197,198]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/httpRoutes@2023-10-01-preview","ScopeType":0,"Body":190}},{"6":{"Value":"Applications.Core/secretStores"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/secretStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":202,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":203,"Flags":10,"Description":"The resource api version"},"properties":{"Type":205,"Flags":0,"Description":"The properties of SecretStore"},"tags":{"Type":223,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"SecretStoreProperties","Properties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":213,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."},"type":{"Type":216,"Flags":0,"Description":"The type of SecretStore data"},"data":{"Type":222,"Flags":1,"Description":"An object to represent key-value type secrets"},"resource":{"Type":4,"Flags":0,"Description":"The resource id of external secret store."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[206,207,208,209,210,211,212]}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[214,215]}},{"2":{"Name":"SecretValueProperties","Properties":{"encoding":{"Type":220,"Flags":0,"Description":"The type of SecretValue Encoding"},"value":{"Type":4,"Flags":0,"Description":"The value of secret."},"valueFrom":{"Type":221,"Flags":0,"Description":"The Secret value source properties"}}}},{"6":{"Value":"raw"}},{"6":{"Value":"base64"}},{"5":{"Elements":[218,219]}},{"2":{"Name":"ValueFromProperties","Properties":{"name":{"Type":4,"Flags":1,"Description":"The name of the referenced secret."},"version":{"Type":4,"Flags":0,"Description":"The version of the referenced secret."}}}},{"2":{"Name":"SecretStorePropertiesData","Properties":{},"AdditionalProperties":217}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/secretStores@2023-10-01-preview","ScopeType":0,"Body":204}},{"6":{"Value":"Applications.Core/volumes"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Core/volumes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":225,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":226,"Flags":10,"Description":"The resource api version"},"properties":{"Type":228,"Flags":0,"Description":"Volume properties"},"tags":{"Type":260,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":47,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"7":{"Name":"VolumeProperties","Discriminator":"kind","BaseProperties":{"environment":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID for the environment that the portable resource is linked to (if applicable)"},"application":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the application that the portable resource is consumed by"},"provisioningState":{"Type":236,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":35,"Flags":2,"Description":"Status of a resource."}},"Elements":{"azure.com.keyvault":237}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[229,230,231,232,233,234,235]}},{"2":{"Name":"AzureKeyVaultVolumeProperties","Properties":{"certificates":{"Type":250,"Flags":0,"Description":"The KeyVault certificates that this volume exposes"},"keys":{"Type":252,"Flags":0,"Description":"The KeyVault keys that this volume exposes"},"resource":{"Type":4,"Flags":1,"Description":"The ID of the keyvault to use for this volume resource"},"secrets":{"Type":258,"Flags":0,"Description":"The KeyVault secrets that this volume exposes"},"kind":{"Type":259,"Flags":1,"Description":"Discriminator property for VolumeProperties."}}}},{"2":{"Name":"CertificateObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":242,"Flags":0,"Description":"Represents secret encodings"},"format":{"Type":245,"Flags":0,"Description":"Represents certificate formats"},"name":{"Type":4,"Flags":1,"Description":"The name of the certificate"},"certType":{"Type":249,"Flags":0,"Description":"Represents certificate types"},"version":{"Type":4,"Flags":0,"Description":"Certificate version"}}}},{"6":{"Value":"utf-8"}},{"6":{"Value":"hex"}},{"6":{"Value":"base64"}},{"5":{"Elements":[239,240,241]}},{"6":{"Value":"pem"}},{"6":{"Value":"pfx"}},{"5":{"Elements":[243,244]}},{"6":{"Value":"certificate"}},{"6":{"Value":"privatekey"}},{"6":{"Value":"publickey"}},{"5":{"Elements":[246,247,248]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesCertificates","Properties":{},"AdditionalProperties":238}},{"2":{"Name":"KeyObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"name":{"Type":4,"Flags":1,"Description":"The name of the key"},"version":{"Type":4,"Flags":0,"Description":"Key version"}}}},{"2":{"Name":"AzureKeyVaultVolumePropertiesKeys","Properties":{},"AdditionalProperties":251}},{"2":{"Name":"SecretObjectProperties","Properties":{"alias":{"Type":4,"Flags":0,"Description":"File name when written to disk"},"encoding":{"Type":257,"Flags":0,"Description":"Represents secret encodings"},"name":{"Type":4,"Flags":1,"Description":"The name of the secret"},"version":{"Type":4,"Flags":0,"Description":"secret version"}}}},{"6":{"Value":"utf-8"}},{"6":{"Value":"hex"}},{"6":{"Value":"base64"}},{"5":{"Elements":[254,255,256]}},{"2":{"Name":"AzureKeyVaultVolumePropertiesSecrets","Properties":{},"AdditionalProperties":253}},{"6":{"Value":"azure.com.keyvault"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Core/volumes@2023-10-01-preview","ScopeType":0,"Body":227}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/extenders","ApiVersion":"2023-10-01-preview","Output":0,"Input":0}},{"2":{"Name":"SecretStoreListSecretsResult","Properties":{"type":{"Type":266,"Flags":2,"Description":"The type of SecretStore data"},"data":{"Type":267,"Flags":2,"Description":"An object to represent key-value type secrets"}}}},{"6":{"Value":"generic"}},{"6":{"Value":"certificate"}},{"5":{"Elements":[264,265]}},{"2":{"Name":"SecretStoreListSecretsResultData","Properties":{},"AdditionalProperties":217}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Core/secretStores","ApiVersion":"2023-10-01-preview","Output":263,"Input":0}}] \ No newline at end of file diff --git a/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.md b/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.md index e6fcd02795..9b83cc3fe5 100644 --- a/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.md +++ b/hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.md @@ -158,6 +158,7 @@ ### Properties * **compute**: [EnvironmentCompute](#environmentcompute): Represents backing compute resource * **outputResources**: [OutputResource](#outputresource)[]: Properties of an output resource +* **recipe**: [RecipeStatus](#recipestatus) (ReadOnly): Recipe status at deployment time for a resource. ## EnvironmentCompute * **Discriminator**: kind @@ -183,6 +184,12 @@ * **localId**: string: 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. * **radiusManaged**: bool: Determines whether Radius manages the lifecycle of the underlying resource. +## RecipeStatus +### Properties +* **templateKind**: string (Required): TemplateKind is the kind of the recipe template used by the portable resource upon deployment. +* **templatePath**: string (Required): TemplatePath is the path of the recipe consumed by the portable resource upon deployment. +* **templateVersion**: string: TemplateVersion is the version number of the template. + ## SystemData ### Properties * **createdAt**: string: The timestamp of resource creation (UTC). diff --git a/hack/bicep-types-radius/generated/applications/applications.dapr/2023-10-01-preview/types.json b/hack/bicep-types-radius/generated/applications/applications.dapr/2023-10-01-preview/types.json index d5fd7fb12d..fe418ab7ba 100644 --- a/hack/bicep-types-radius/generated/applications/applications.dapr/2023-10-01-preview/types.json +++ b/hack/bicep-types-radius/generated/applications/applications.dapr/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.Dapr/pubSubBrokers"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Dapr/pubSubBrokers","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":0,"Description":"Dapr PubSubBroker portable resource properties"},"tags":{"Type":36,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":37,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"DaprPubSubBrokerProperties","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":19,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"componentName":{"Type":4,"Flags":2,"Description":"The name of the Dapr component object. Use this value in your code when interacting with the Dapr client to use the Dapr component."},"metadata":{"Type":0,"Flags":0,"Description":"Any object"},"type":{"Type":4,"Flags":0,"Description":"Dapr component type which must matches the format used by Dapr Kubernetes configuration format"},"version":{"Type":4,"Flags":0,"Description":"Dapr component version"},"resources":{"Type":31,"Flags":0,"Description":"A collection of references to resources associated with the pubSubBroker"},"recipe":{"Type":32,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":35,"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."}}}},{"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]}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":21,"Flags":0,"Description":"Represents backing compute resource"},"outputResources":{"Type":29,"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":22,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":26}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":25,"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":[23,24]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":27,"Flags":1,"Description":"Discriminator property for EnvironmentCompute."}}}},{"6":{"Value":"kubernetes"}},{"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":28}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":30}},{"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":[33,34]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":42,"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":47,"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":[38,39,40,41]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[43,44,45,46]}},{"4":{"Name":"Applications.Dapr/pubSubBrokers@2023-10-01-preview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Dapr/secretStores"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Dapr/secretStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":49,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":50,"Flags":10,"Description":"The resource api version"},"properties":{"Type":52,"Flags":0,"Description":"Dapr SecretStore portable resource properties"},"tags":{"Type":64,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":37,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"DaprSecretStoreProperties","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":60,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"componentName":{"Type":4,"Flags":2,"Description":"The name of the Dapr component object. Use this value in your code when interacting with the Dapr client to use the Dapr component."},"metadata":{"Type":0,"Flags":0,"Description":"Any object"},"type":{"Type":4,"Flags":0,"Description":"Dapr component type which must matches the format used by Dapr Kubernetes configuration format"},"version":{"Type":4,"Flags":0,"Description":"Dapr component version"},"recipe":{"Type":32,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":63,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[53,54,55,56,57,58,59]}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[61,62]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Dapr/secretStores@2023-10-01-preview","ScopeType":0,"Body":51}},{"6":{"Value":"Applications.Dapr/stateStores"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Dapr/stateStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":66,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":67,"Flags":10,"Description":"The resource api version"},"properties":{"Type":69,"Flags":0,"Description":"Dapr StateStore portable resource properties"},"tags":{"Type":82,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":37,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"DaprStateStoreProperties","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":77,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"componentName":{"Type":4,"Flags":2,"Description":"The name of the Dapr component object. Use this value in your code when interacting with the Dapr client to use the Dapr component."},"metadata":{"Type":0,"Flags":0,"Description":"Any object"},"type":{"Type":4,"Flags":0,"Description":"Dapr component type which must matches the format used by Dapr Kubernetes configuration format"},"version":{"Type":4,"Flags":0,"Description":"Dapr component version"},"resources":{"Type":78,"Flags":0,"Description":"A collection of references to resources associated with the state store"},"recipe":{"Type":32,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":81,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[70,71,72,73,74,75,76]}},{"3":{"ItemType":30}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[79,80]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Dapr/stateStores@2023-10-01-preview","ScopeType":0,"Body":68}}] \ 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.Dapr/pubSubBrokers"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Dapr/pubSubBrokers","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":0,"Description":"Dapr PubSubBroker portable resource properties"},"tags":{"Type":37,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":38,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"DaprPubSubBrokerProperties","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":19,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"componentName":{"Type":4,"Flags":2,"Description":"The name of the Dapr component object. Use this value in your code when interacting with the Dapr client to use the Dapr component."},"metadata":{"Type":0,"Flags":0,"Description":"Any object"},"type":{"Type":4,"Flags":0,"Description":"Dapr component type which must matches the format used by Dapr Kubernetes configuration format"},"version":{"Type":4,"Flags":0,"Description":"Dapr component version"},"resources":{"Type":32,"Flags":0,"Description":"A collection of references to resources associated with the pubSubBroker"},"recipe":{"Type":33,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":36,"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."}}}},{"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]}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":21,"Flags":0,"Description":"Represents backing compute resource"},"recipe":{"Type":28,"Flags":2,"Description":"Recipe status at deployment time for a resource."},"outputResources":{"Type":30,"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":22,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":26}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":25,"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":[23,24]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":27,"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":29}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":31}},{"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":[34,35]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":43,"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":48,"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":[39,40,41,42]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[44,45,46,47]}},{"4":{"Name":"Applications.Dapr/pubSubBrokers@2023-10-01-preview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Dapr/secretStores"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Dapr/secretStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":50,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":51,"Flags":10,"Description":"The resource api version"},"properties":{"Type":53,"Flags":0,"Description":"Dapr SecretStore portable resource properties"},"tags":{"Type":65,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":38,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"DaprSecretStoreProperties","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":61,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"componentName":{"Type":4,"Flags":2,"Description":"The name of the Dapr component object. Use this value in your code when interacting with the Dapr client to use the Dapr component."},"metadata":{"Type":0,"Flags":0,"Description":"Any object"},"type":{"Type":4,"Flags":0,"Description":"Dapr component type which must matches the format used by Dapr Kubernetes configuration format"},"version":{"Type":4,"Flags":0,"Description":"Dapr component version"},"recipe":{"Type":33,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":64,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[54,55,56,57,58,59,60]}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[62,63]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Dapr/secretStores@2023-10-01-preview","ScopeType":0,"Body":52}},{"6":{"Value":"Applications.Dapr/stateStores"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Dapr/stateStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":67,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":68,"Flags":10,"Description":"The resource api version"},"properties":{"Type":70,"Flags":0,"Description":"Dapr StateStore portable resource properties"},"tags":{"Type":83,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":38,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"DaprStateStoreProperties","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":78,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"componentName":{"Type":4,"Flags":2,"Description":"The name of the Dapr component object. Use this value in your code when interacting with the Dapr client to use the Dapr component."},"metadata":{"Type":0,"Flags":0,"Description":"Any object"},"type":{"Type":4,"Flags":0,"Description":"Dapr component type which must matches the format used by Dapr Kubernetes configuration format"},"version":{"Type":4,"Flags":0,"Description":"Dapr component version"},"resources":{"Type":79,"Flags":0,"Description":"A collection of references to resources associated with the state store"},"recipe":{"Type":33,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":82,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[71,72,73,74,75,76,77]}},{"3":{"ItemType":31}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[80,81]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Dapr/stateStores@2023-10-01-preview","ScopeType":0,"Body":69}}] \ No newline at end of file diff --git a/hack/bicep-types-radius/generated/applications/applications.dapr/2023-10-01-preview/types.md b/hack/bicep-types-radius/generated/applications/applications.dapr/2023-10-01-preview/types.md index 004dff25e9..88efa3a37e 100644 --- a/hack/bicep-types-radius/generated/applications/applications.dapr/2023-10-01-preview/types.md +++ b/hack/bicep-types-radius/generated/applications/applications.dapr/2023-10-01-preview/types.md @@ -63,6 +63,7 @@ ### Properties * **compute**: [EnvironmentCompute](#environmentcompute): Represents backing compute resource * **outputResources**: [OutputResource](#outputresource)[]: Properties of an output resource +* **recipe**: [RecipeStatus](#recipestatus) (ReadOnly): Recipe status at deployment time for a resource. ## EnvironmentCompute * **Discriminator**: kind @@ -88,6 +89,12 @@ * **localId**: string: 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. * **radiusManaged**: bool: Determines whether Radius manages the lifecycle of the underlying resource. +## RecipeStatus +### Properties +* **templateKind**: string (Required): TemplateKind is the kind of the recipe template used by the portable resource upon deployment. +* **templatePath**: string (Required): TemplatePath is the path of the recipe consumed by the portable resource upon deployment. +* **templateVersion**: string: TemplateVersion is the version number of the template. + ## SystemData ### Properties * **createdAt**: string: The timestamp of resource creation (UTC). diff --git a/hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.json b/hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.json index 4cedfdb8e5..a47bd71085 100644 --- a/hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.json +++ b/hack/bicep-types-radius/generated/applications/applications.datastores/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.Datastores/mongoDatabases"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Datastores/mongoDatabases","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":0,"Description":"MongoDatabase portable resource properties"},"tags":{"Type":37,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":38,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"MongoDatabaseProperties","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":19,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":30,"Flags":0,"Description":"The secret values for the given MongoDatabase resource"},"host":{"Type":4,"Flags":0,"Description":"Host name of the target Mongo database"},"port":{"Type":3,"Flags":0,"Description":"Port value of the target Mongo database"},"database":{"Type":4,"Flags":0,"Description":"Database name of the target Mongo database"},"resources":{"Type":32,"Flags":0,"Description":"List of the resource IDs that support the MongoDB resource"},"username":{"Type":4,"Flags":0,"Description":"Username to use when connecting to the target Mongo database"},"recipe":{"Type":33,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":36,"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."}}}},{"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]}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":21,"Flags":0,"Description":"Represents backing compute resource"},"outputResources":{"Type":29,"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":22,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":26}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":25,"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":[23,24]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":27,"Flags":1,"Description":"Discriminator property for EnvironmentCompute."}}}},{"6":{"Value":"kubernetes"}},{"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":28}},{"2":{"Name":"MongoDatabaseSecrets","Properties":{"password":{"Type":4,"Flags":0,"Description":"Password to use when connecting to the target Mongo database"},"connectionString":{"Type":4,"Flags":0,"Description":"Connection string used to connect to the target Mongo database"}}}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":31}},{"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":[34,35]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":43,"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":48,"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":[39,40,41,42]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[44,45,46,47]}},{"4":{"Name":"Applications.Datastores/mongoDatabases@2023-10-01-preview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Datastores/redisCaches"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Datastores/redisCaches","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":50,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":51,"Flags":10,"Description":"The resource api version"},"properties":{"Type":53,"Flags":0,"Description":"RedisCache portable resource properties"},"tags":{"Type":67,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":38,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"RedisCacheProperties","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":61,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":62,"Flags":0,"Description":"The secret values for the given RedisCache resource"},"host":{"Type":4,"Flags":0,"Description":"The host name of the target Redis cache"},"port":{"Type":3,"Flags":0,"Description":"The port value of the target Redis cache"},"username":{"Type":4,"Flags":0,"Description":"The username for Redis cache"},"tls":{"Type":2,"Flags":0,"Description":"Specifies whether to enable SSL connections to the Redis cache"},"resources":{"Type":63,"Flags":0,"Description":"List of the resource IDs that support the Redis resource"},"recipe":{"Type":33,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":66,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[54,55,56,57,58,59,60]}},{"2":{"Name":"RedisCacheSecrets","Properties":{"connectionString":{"Type":4,"Flags":0,"Description":"The connection string used to connect to the Redis cache"},"password":{"Type":4,"Flags":0,"Description":"The password for this Redis cache instance"},"url":{"Type":4,"Flags":0,"Description":"The URL used to connect to the Redis cache"}}}},{"3":{"ItemType":31}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[64,65]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Datastores/redisCaches@2023-10-01-preview","ScopeType":0,"Body":52}},{"6":{"Value":"Applications.Datastores/sqlDatabases"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Datastores/sqlDatabases","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":69,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":70,"Flags":10,"Description":"The resource api version"},"properties":{"Type":72,"Flags":0,"Description":"SqlDatabase properties"},"tags":{"Type":86,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":38,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"SqlDatabaseProperties","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":80,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"database":{"Type":4,"Flags":0,"Description":"The name of the Sql database."},"server":{"Type":4,"Flags":0,"Description":"The fully qualified domain name of the Sql database."},"port":{"Type":3,"Flags":0,"Description":"Port value of the target Sql database"},"username":{"Type":4,"Flags":0,"Description":"Username to use when connecting to the target Sql database"},"resources":{"Type":81,"Flags":0,"Description":"List of the resource IDs that support the SqlDatabase resource"},"secrets":{"Type":82,"Flags":0,"Description":"The secret values for the given SqlDatabase resource"},"recipe":{"Type":33,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":85,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[73,74,75,76,77,78,79]}},{"3":{"ItemType":31}},{"2":{"Name":"SqlDatabaseSecrets","Properties":{"password":{"Type":4,"Flags":0,"Description":"Password to use when connecting to the target Sql database"},"connectionString":{"Type":4,"Flags":0,"Description":"Connection string used to connect to the target Sql database"}}}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[83,84]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Datastores/sqlDatabases@2023-10-01-preview","ScopeType":0,"Body":71}},{"2":{"Name":"MongoDatabaseListSecretsResult","Properties":{"password":{"Type":4,"Flags":2,"Description":"Password to use when connecting to the target Mongo database"},"connectionString":{"Type":4,"Flags":2,"Description":"Connection string used to connect to the target Mongo database"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Datastores/mongoDatabases","ApiVersion":"2023-10-01-preview","Output":88,"Input":0}},{"2":{"Name":"RedisCacheListSecretsResult","Properties":{"connectionString":{"Type":4,"Flags":2,"Description":"The connection string used to connect to the Redis cache"},"password":{"Type":4,"Flags":2,"Description":"The password for this Redis cache instance"},"url":{"Type":4,"Flags":2,"Description":"The URL used to connect to the Redis cache"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Datastores/redisCaches","ApiVersion":"2023-10-01-preview","Output":90,"Input":0}},{"2":{"Name":"SqlDatabaseListSecretsResult","Properties":{"password":{"Type":4,"Flags":2,"Description":"Password to use when connecting to the target Sql database"},"connectionString":{"Type":4,"Flags":2,"Description":"Connection string used to connect to the target Sql database"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Datastores/sqlDatabases","ApiVersion":"2023-10-01-preview","Output":92,"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.Datastores/mongoDatabases"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Datastores/mongoDatabases","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":0,"Description":"MongoDatabase portable resource properties"},"tags":{"Type":38,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":39,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"MongoDatabaseProperties","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":19,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":31,"Flags":0,"Description":"The secret values for the given MongoDatabase resource"},"host":{"Type":4,"Flags":0,"Description":"Host name of the target Mongo database"},"port":{"Type":3,"Flags":0,"Description":"Port value of the target Mongo database"},"database":{"Type":4,"Flags":0,"Description":"Database name of the target Mongo database"},"resources":{"Type":33,"Flags":0,"Description":"List of the resource IDs that support the MongoDB resource"},"username":{"Type":4,"Flags":0,"Description":"Username to use when connecting to the target Mongo database"},"recipe":{"Type":34,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":37,"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."}}}},{"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]}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":21,"Flags":0,"Description":"Represents backing compute resource"},"recipe":{"Type":28,"Flags":2,"Description":"Recipe status at deployment time for a resource."},"outputResources":{"Type":30,"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":22,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":26}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":25,"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":[23,24]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":27,"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":29}},{"2":{"Name":"MongoDatabaseSecrets","Properties":{"password":{"Type":4,"Flags":0,"Description":"Password to use when connecting to the target Mongo database"},"connectionString":{"Type":4,"Flags":0,"Description":"Connection string used to connect to the target Mongo database"}}}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":32}},{"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":[35,36]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":44,"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":49,"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":[40,41,42,43]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[45,46,47,48]}},{"4":{"Name":"Applications.Datastores/mongoDatabases@2023-10-01-preview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Datastores/redisCaches"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Datastores/redisCaches","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":51,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":52,"Flags":10,"Description":"The resource api version"},"properties":{"Type":54,"Flags":0,"Description":"RedisCache portable resource properties"},"tags":{"Type":68,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":39,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"RedisCacheProperties","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":62,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":63,"Flags":0,"Description":"The secret values for the given RedisCache resource"},"host":{"Type":4,"Flags":0,"Description":"The host name of the target Redis cache"},"port":{"Type":3,"Flags":0,"Description":"The port value of the target Redis cache"},"username":{"Type":4,"Flags":0,"Description":"The username for Redis cache"},"tls":{"Type":2,"Flags":0,"Description":"Specifies whether to enable SSL connections to the Redis cache"},"resources":{"Type":64,"Flags":0,"Description":"List of the resource IDs that support the Redis resource"},"recipe":{"Type":34,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":67,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[55,56,57,58,59,60,61]}},{"2":{"Name":"RedisCacheSecrets","Properties":{"connectionString":{"Type":4,"Flags":0,"Description":"The connection string used to connect to the Redis cache"},"password":{"Type":4,"Flags":0,"Description":"The password for this Redis cache instance"},"url":{"Type":4,"Flags":0,"Description":"The URL used to connect to the Redis cache"}}}},{"3":{"ItemType":32}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[65,66]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Datastores/redisCaches@2023-10-01-preview","ScopeType":0,"Body":53}},{"6":{"Value":"Applications.Datastores/sqlDatabases"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Datastores/sqlDatabases","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":70,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":71,"Flags":10,"Description":"The resource api version"},"properties":{"Type":73,"Flags":0,"Description":"SqlDatabase properties"},"tags":{"Type":87,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":39,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"SqlDatabaseProperties","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":81,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"database":{"Type":4,"Flags":0,"Description":"The name of the Sql database."},"server":{"Type":4,"Flags":0,"Description":"The fully qualified domain name of the Sql database."},"port":{"Type":3,"Flags":0,"Description":"Port value of the target Sql database"},"username":{"Type":4,"Flags":0,"Description":"Username to use when connecting to the target Sql database"},"resources":{"Type":82,"Flags":0,"Description":"List of the resource IDs that support the SqlDatabase resource"},"secrets":{"Type":83,"Flags":0,"Description":"The secret values for the given SqlDatabase resource"},"recipe":{"Type":34,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":86,"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."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Provisioning"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Accepted"}},{"5":{"Elements":[74,75,76,77,78,79,80]}},{"3":{"ItemType":32}},{"2":{"Name":"SqlDatabaseSecrets","Properties":{"password":{"Type":4,"Flags":0,"Description":"Password to use when connecting to the target Sql database"},"connectionString":{"Type":4,"Flags":0,"Description":"Connection string used to connect to the target Sql database"}}}},{"6":{"Value":"recipe"}},{"6":{"Value":"manual"}},{"5":{"Elements":[84,85]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Datastores/sqlDatabases@2023-10-01-preview","ScopeType":0,"Body":72}},{"2":{"Name":"MongoDatabaseListSecretsResult","Properties":{"password":{"Type":4,"Flags":2,"Description":"Password to use when connecting to the target Mongo database"},"connectionString":{"Type":4,"Flags":2,"Description":"Connection string used to connect to the target Mongo database"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Datastores/mongoDatabases","ApiVersion":"2023-10-01-preview","Output":89,"Input":0}},{"2":{"Name":"RedisCacheListSecretsResult","Properties":{"connectionString":{"Type":4,"Flags":2,"Description":"The connection string used to connect to the Redis cache"},"password":{"Type":4,"Flags":2,"Description":"The password for this Redis cache instance"},"url":{"Type":4,"Flags":2,"Description":"The URL used to connect to the Redis cache"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Datastores/redisCaches","ApiVersion":"2023-10-01-preview","Output":91,"Input":0}},{"2":{"Name":"SqlDatabaseListSecretsResult","Properties":{"password":{"Type":4,"Flags":2,"Description":"Password to use when connecting to the target Sql database"},"connectionString":{"Type":4,"Flags":2,"Description":"Connection string used to connect to the target Sql database"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Datastores/sqlDatabases","ApiVersion":"2023-10-01-preview","Output":93,"Input":0}}] \ No newline at end of file diff --git a/hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.md b/hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.md index 119a1879d6..6b7202cdf3 100644 --- a/hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.md +++ b/hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.md @@ -87,6 +87,7 @@ ### Properties * **compute**: [EnvironmentCompute](#environmentcompute): Represents backing compute resource * **outputResources**: [OutputResource](#outputresource)[]: Properties of an output resource +* **recipe**: [RecipeStatus](#recipestatus) (ReadOnly): Recipe status at deployment time for a resource. ## EnvironmentCompute * **Discriminator**: kind @@ -112,6 +113,12 @@ * **localId**: string: 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. * **radiusManaged**: bool: Determines whether Radius manages the lifecycle of the underlying resource. +## RecipeStatus +### Properties +* **templateKind**: string (Required): TemplateKind is the kind of the recipe template used by the portable resource upon deployment. +* **templatePath**: string (Required): TemplatePath is the path of the recipe consumed by the portable resource upon deployment. +* **templateVersion**: string: TemplateVersion is the version number of the template. + ## SystemData ### Properties * **createdAt**: string: The timestamp of resource creation (UTC). diff --git a/hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.json b/hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.json index f307bb6d7c..a20a71c8ed 100644 --- a/hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.json +++ b/hack/bicep-types-radius/generated/applications/applications.messaging/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.Messaging/rabbitMQQueues"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Messaging/rabbitMQQueues","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":0,"Description":"RabbitMQQueue portable resource properties"},"tags":{"Type":37,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":38,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"RabbitMQQueueProperties","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":19,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":30,"Flags":0,"Description":"The connection secrets properties to the RabbitMQ instance"},"queue":{"Type":4,"Flags":0,"Description":"The name of the queue"},"host":{"Type":4,"Flags":0,"Description":"The hostname of the RabbitMQ instance"},"port":{"Type":3,"Flags":0,"Description":"The port of the RabbitMQ instance. Defaults to 5672"},"vHost":{"Type":4,"Flags":0,"Description":"The RabbitMQ virtual host (vHost) the client will connect to. Defaults to no vHost."},"username":{"Type":4,"Flags":0,"Description":"The username to use when connecting to the RabbitMQ instance"},"resources":{"Type":32,"Flags":0,"Description":"List of the resource IDs that support the rabbitMQ resource"},"tls":{"Type":2,"Flags":0,"Description":"Specifies whether to use SSL when connecting to the RabbitMQ instance"},"recipe":{"Type":33,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":36,"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."}}}},{"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]}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":21,"Flags":0,"Description":"Represents backing compute resource"},"outputResources":{"Type":29,"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":22,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":26}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":25,"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":[23,24]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":27,"Flags":1,"Description":"Discriminator property for EnvironmentCompute."}}}},{"6":{"Value":"kubernetes"}},{"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":28}},{"2":{"Name":"RabbitMQSecrets","Properties":{"password":{"Type":4,"Flags":0,"Description":"The password used to connect to the RabbitMQ instance"},"uri":{"Type":4,"Flags":0,"Description":"The connection URI of the RabbitMQ instance. Generated automatically from host, port, SSL, username, password, and vhost. Can be overridden with a custom value"}}}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":31}},{"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":[34,35]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":43,"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":48,"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":[39,40,41,42]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[44,45,46,47]}},{"4":{"Name":"Applications.Messaging/rabbitMQQueues@2023-10-01-preview","ScopeType":0,"Body":10}},{"2":{"Name":"RabbitMQListSecretsResult","Properties":{"password":{"Type":4,"Flags":2,"Description":"The password used to connect to the RabbitMQ instance"},"uri":{"Type":4,"Flags":2,"Description":"The connection URI of the RabbitMQ instance. Generated automatically from host, port, SSL, username, password, and vhost. Can be overridden with a custom value"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Messaging/rabbitMQQueues","ApiVersion":"2023-10-01-preview","Output":50,"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.Messaging/rabbitMQQueues"}},{"6":{"Value":"2023-10-01-preview"}},{"2":{"Name":"Applications.Messaging/rabbitMQQueues","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":0,"Description":"RabbitMQQueue portable resource properties"},"tags":{"Type":38,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":39,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."}}}},{"2":{"Name":"RabbitMQQueueProperties","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":19,"Flags":2,"Description":"Provisioning state of the portable resource at the time the operation was called"},"status":{"Type":20,"Flags":2,"Description":"Status of a resource."},"secrets":{"Type":31,"Flags":0,"Description":"The connection secrets properties to the RabbitMQ instance"},"queue":{"Type":4,"Flags":0,"Description":"The name of the queue"},"host":{"Type":4,"Flags":0,"Description":"The hostname of the RabbitMQ instance"},"port":{"Type":3,"Flags":0,"Description":"The port of the RabbitMQ instance. Defaults to 5672"},"vHost":{"Type":4,"Flags":0,"Description":"The RabbitMQ virtual host (vHost) the client will connect to. Defaults to no vHost."},"username":{"Type":4,"Flags":0,"Description":"The username to use when connecting to the RabbitMQ instance"},"resources":{"Type":33,"Flags":0,"Description":"List of the resource IDs that support the rabbitMQ resource"},"tls":{"Type":2,"Flags":0,"Description":"Specifies whether to use SSL when connecting to the RabbitMQ instance"},"recipe":{"Type":34,"Flags":0,"Description":"The recipe used to automatically deploy underlying infrastructure for a portable resource"},"resourceProvisioning":{"Type":37,"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."}}}},{"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]}},{"2":{"Name":"ResourceStatus","Properties":{"compute":{"Type":21,"Flags":0,"Description":"Represents backing compute resource"},"recipe":{"Type":28,"Flags":2,"Description":"Recipe status at deployment time for a resource."},"outputResources":{"Type":30,"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":22,"Flags":0,"Description":"IdentitySettings is the external identity setting."}},"Elements":{"kubernetes":26}}},{"2":{"Name":"IdentitySettings","Properties":{"kind":{"Type":25,"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":[23,24]}},{"2":{"Name":"KubernetesCompute","Properties":{"namespace":{"Type":4,"Flags":1,"Description":"The namespace to use for the environment."},"kind":{"Type":27,"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":29}},{"2":{"Name":"RabbitMQSecrets","Properties":{"password":{"Type":4,"Flags":0,"Description":"The password used to connect to the RabbitMQ instance"},"uri":{"Type":4,"Flags":0,"Description":"The connection URI of the RabbitMQ instance. Generated automatically from host, port, SSL, username, password, and vhost. Can be overridden with a custom value"}}}},{"2":{"Name":"ResourceReference","Properties":{"id":{"Type":4,"Flags":1,"Description":"Resource id of an existing resource"}}}},{"3":{"ItemType":32}},{"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":[35,36]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":44,"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":49,"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":[40,41,42,43]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[45,46,47,48]}},{"4":{"Name":"Applications.Messaging/rabbitMQQueues@2023-10-01-preview","ScopeType":0,"Body":10}},{"2":{"Name":"RabbitMQListSecretsResult","Properties":{"password":{"Type":4,"Flags":2,"Description":"The password used to connect to the RabbitMQ instance"},"uri":{"Type":4,"Flags":2,"Description":"The connection URI of the RabbitMQ instance. Generated automatically from host, port, SSL, username, password, and vhost. Can be overridden with a custom value"}}}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Messaging/rabbitMQQueues","ApiVersion":"2023-10-01-preview","Output":51,"Input":0}}] \ No newline at end of file diff --git a/hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.md b/hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.md index e31bb0495e..0853c80e98 100644 --- a/hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.md +++ b/hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.md @@ -53,6 +53,7 @@ ### Properties * **compute**: [EnvironmentCompute](#environmentcompute): Represents backing compute resource * **outputResources**: [OutputResource](#outputresource)[]: Properties of an output resource +* **recipe**: [RecipeStatus](#recipestatus) (ReadOnly): Recipe status at deployment time for a resource. ## EnvironmentCompute * **Discriminator**: kind @@ -78,6 +79,12 @@ * **localId**: string: 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. * **radiusManaged**: bool: Determines whether Radius manages the lifecycle of the underlying resource. +## RecipeStatus +### Properties +* **templateKind**: string (Required): TemplateKind is the kind of the recipe template used by the portable resource upon deployment. +* **templatePath**: string (Required): TemplatePath is the path of the recipe consumed by the portable resource upon deployment. +* **templateVersion**: string: TemplateVersion is the version number of the template. + ## SystemData ### Properties * **createdAt**: string: The timestamp of resource creation (UTC). diff --git a/hack/bicep-types-radius/generated/index.json b/hack/bicep-types-radius/generated/index.json index 7790b45b3d..735c06d6d0 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":57},"Applications.Core/containers@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":122},"Applications.Core/environments@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":147},"Applications.Core/extenders@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":165},"Applications.Core/gateways@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":186},"Applications.Core/httpRoutes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":200},"Applications.Core/secretStores@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":223},"Applications.Core/volumes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":260},"Applications.Dapr/pubSubBrokers@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":48},"Applications.Dapr/secretStores@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":65},"Applications.Dapr/stateStores@2023-10-01-preview":{"RelativePath":"applications/applications.dapr/2023-10-01-preview/types.json","Index":83},"Applications.Datastores/mongoDatabases@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":49},"Applications.Datastores/redisCaches@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":68},"Applications.Datastores/sqlDatabases@2023-10-01-preview":{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":87},"Applications.Messaging/rabbitMQQueues@2023-10-01-preview":{"RelativePath":"applications/applications.messaging/2023-10-01-preview/types.json","Index":49}},"Functions":{"applications.core/extenders":{"2023-10-01-preview":[{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":261}]},"applications.core/secretstores":{"2023-10-01-preview":[{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":267}]},"applications.datastores/mongodatabases":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":89}]},"applications.datastores/rediscaches":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":91}]},"applications.datastores/sqldatabases":{"2023-10-01-preview":[{"RelativePath":"applications/applications.datastores/2023-10-01-preview/types.json","Index":93}]},"applications.messaging/rabbitmqqueues":{"2023-10-01-preview":[{"RelativePath":"applications/applications.messaging/2023-10-01-preview/types.json","Index":51}]}}} \ 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":148},"Applications.Core/extenders@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":166},"Applications.Core/gateways@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":187},"Applications.Core/httpRoutes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":201},"Applications.Core/secretStores@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":224},"Applications.Core/volumes@2023-10-01-preview":{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":261},"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":262}]},"applications.core/secretstores":{"2023-10-01-preview":[{"RelativePath":"applications/applications.core/2023-10-01-preview/types.json","Index":268}]},"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/pkg/corerp/api/v20231001preview/extender_conversion.go b/pkg/corerp/api/v20231001preview/extender_conversion.go index 41df64ef60..199eba6468 100644 --- a/pkg/corerp/api/v20231001preview/extender_conversion.go +++ b/pkg/corerp/api/v20231001preview/extender_conversion.go @@ -78,6 +78,7 @@ func (dst *ExtenderResource) ConvertFrom(src v1.DataModelInterface) error { dst.Properties = &ExtenderProperties{ Status: &ResourceStatus{ OutputResources: toOutputResourcesDataModel(extender.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(extender.Properties.Status.Recipe), }, ProvisioningState: fromProvisioningStateDataModel(extender.InternalMetadata.AsyncProvisioningState), Environment: to.Ptr(extender.Properties.Environment), @@ -87,6 +88,7 @@ func (dst *ExtenderResource) ConvertFrom(src v1.DataModelInterface) error { ResourceProvisioning: fromResourceProvisioningDataModel(extender.Properties.ResourceProvisioning), // Secrets are omitted. } + return nil } @@ -116,6 +118,23 @@ func fromResourceProvisioningDataModel(provisioning portableresources.ResourcePr return &converted } +func fromRecipeStatus(recipeStatus *rpv1.RecipeStatus) *RecipeStatus { + if recipeStatus == nil { + return nil + } + + status := &RecipeStatus{ + TemplateKind: to.Ptr(recipeStatus.TemplateKind), + TemplatePath: to.Ptr(recipeStatus.TemplatePath), + } + + if recipeStatus.TemplateVersion != "" { + status.TemplateVersion = to.Ptr(recipeStatus.TemplateVersion) + } + + return status +} + func fromRecipeDataModel(r portableresources.ResourceRecipe) *Recipe { return &Recipe{ Name: to.Ptr(r.Name), diff --git a/pkg/corerp/api/v20231001preview/extender_conversion_test.go b/pkg/corerp/api/v20231001preview/extender_conversion_test.go index c426b0aeeb..f6fe0f34bf 100644 --- a/pkg/corerp/api/v20231001preview/extender_conversion_test.go +++ b/pkg/corerp/api/v20231001preview/extender_conversion_test.go @@ -204,7 +204,7 @@ func TestExtender_ConvertDataModelToVersioned(t *testing.T) { ResourceProvisioning: to.Ptr(ResourceProvisioningRecipe), ProvisioningState: to.Ptr(ProvisioningStateAccepted), Recipe: &Recipe{Name: to.Ptr("test-recipe"), Parameters: nil}, - Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}), + Status: resourcetypeutil.MustPopulateResourceStatusWithRecipe(&ResourceStatus{}), }, Tags: map[string]*string{ "env": to.Ptr("dev"), diff --git a/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_recipe.json b/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_recipe.json index dd931d5e5e..40d69d4bc1 100644 --- a/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_recipe.json +++ b/pkg/corerp/api/v20231001preview/testdata/extenderdatamodel_recipe.json @@ -19,7 +19,11 @@ { "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource" } - ] + ], + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } }, "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", diff --git a/pkg/corerp/api/v20231001preview/zz_generated_models.go b/pkg/corerp/api/v20231001preview/zz_generated_models.go index 0dba064e6f..1515119ed7 100644 --- a/pkg/corerp/api/v20231001preview/zz_generated_models.go +++ b/pkg/corerp/api/v20231001preview/zz_generated_models.go @@ -1424,6 +1424,18 @@ type RecipePropertiesUpdate struct { // GetRecipePropertiesUpdate implements the RecipePropertiesUpdateClassification interface for type RecipePropertiesUpdate. func (r *RecipePropertiesUpdate) GetRecipePropertiesUpdate() *RecipePropertiesUpdate { return r } +// 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. + TemplateKind *string + + // REQUIRED; TemplatePath is the path of the recipe consumed by the portable resource upon deployment. + TemplatePath *string + + // TemplateVersion is the version number of the template. + TemplateVersion *string +} + // RecipeUpdate - The recipe used to automatically deploy underlying infrastructure for a portable resource type RecipeUpdate struct { // The name of the recipe within the environment to use @@ -1461,6 +1473,9 @@ type ResourceStatus struct { // Properties of an output resource OutputResources []*OutputResource + + // READ-ONLY; The recipe data at the time of deployment + Recipe *RecipeStatus } // RuntimesProperties - The properties for runtime configuration diff --git a/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go b/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go index 3f0732bcc4..894d3202d9 100644 --- a/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go +++ b/pkg/corerp/api/v20231001preview/zz_generated_models_serde.go @@ -3361,6 +3361,41 @@ func (r *RecipePropertiesUpdate) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type RecipeStatus. +func (r RecipeStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "templateKind", r.TemplateKind) + populate(objectMap, "templatePath", r.TemplatePath) + populate(objectMap, "templateVersion", r.TemplateVersion) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RecipeStatus. +func (r *RecipeStatus) 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 "templateKind": + err = unpopulate(val, "TemplateKind", &r.TemplateKind) + delete(rawMsg, key) + case "templatePath": + err = unpopulate(val, "TemplatePath", &r.TemplatePath) + delete(rawMsg, key) + case "templateVersion": + err = unpopulate(val, "TemplateVersion", &r.TemplateVersion) + 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 RecipeUpdate. func (r RecipeUpdate) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -3463,6 +3498,7 @@ func (r ResourceStatus) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "compute", r.Compute) populate(objectMap, "outputResources", r.OutputResources) + populate(objectMap, "recipe", r.Recipe) return json.Marshal(objectMap) } @@ -3481,6 +3517,9 @@ func (r *ResourceStatus) UnmarshalJSON(data []byte) error { case "outputResources": err = unpopulate(val, "OutputResources", &r.OutputResources) delete(rawMsg, key) + case "recipe": + err = unpopulate(val, "Recipe", &r.Recipe) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", r, err) diff --git a/pkg/corerp/processors/extenders/processor.go b/pkg/corerp/processors/extenders/processor.go index 59b08831b0..9dfcee92fb 100644 --- a/pkg/corerp/processors/extenders/processor.go +++ b/pkg/corerp/processors/extenders/processor.go @@ -17,7 +17,7 @@ type Processor struct { // the recipe output with the existing values in the resource. It returns an error if the secret values are not of type string // or if any of the other validations fail. func (p *Processor) Process(ctx context.Context, resource *datamodel.Extender, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.Properties.Status.Recipe) computedValues := mergeOutputValues(resource.Properties.AdditionalProperties, options.RecipeOutput, false) for k, val := range computedValues { diff --git a/pkg/daprrp/api/v20231001preview/datamodel_util.go b/pkg/daprrp/api/v20231001preview/datamodel_util.go index 62dc748fce..180adf7ee0 100644 --- a/pkg/daprrp/api/v20231001preview/datamodel_util.go +++ b/pkg/daprrp/api/v20231001preview/datamodel_util.go @@ -98,6 +98,23 @@ func fromResourceProvisioningDataModel(provisioning portableresources.ResourcePr return &converted } +func fromRecipeStatus(recipeStatus *rpv1.RecipeStatus) *RecipeStatus { + if recipeStatus == nil { + return nil + } + + status := &RecipeStatus{ + TemplateKind: to.Ptr(recipeStatus.TemplateKind), + TemplatePath: to.Ptr(recipeStatus.TemplatePath), + } + + if recipeStatus.TemplateVersion != "" { + status.TemplateVersion = to.Ptr(recipeStatus.TemplateVersion) + } + + return status +} + func fromSystemDataModel(s v1.SystemData) *SystemData { return &SystemData{ CreatedBy: to.Ptr(s.CreatedBy), diff --git a/pkg/daprrp/api/v20231001preview/datamodel_util_test.go b/pkg/daprrp/api/v20231001preview/datamodel_util_test.go index 0d355fa359..414011547d 100644 --- a/pkg/daprrp/api/v20231001preview/datamodel_util_test.go +++ b/pkg/daprrp/api/v20231001preview/datamodel_util_test.go @@ -22,6 +22,8 @@ import ( v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" "github.com/radius-project/radius/pkg/portableresources" + "github.com/radius-project/radius/pkg/recipes" + rpv1 "github.com/radius-project/radius/pkg/rp/v1" "github.com/radius-project/radius/pkg/to" "github.com/stretchr/testify/require" ) @@ -212,6 +214,41 @@ func TestFromResourceProvisiongDataModel(t *testing.T) { } } +func Test_fromRecipeStatus(t *testing.T) { + testCases := []struct { + recipeStatus *rpv1.RecipeStatus + expected *RecipeStatus + }{ + {&rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindTerraform, + TemplatePath: "/path/to/template.tf", + TemplateVersion: "1.0", + }, &RecipeStatus{ + TemplateKind: to.Ptr(recipes.TemplateKindTerraform), + TemplatePath: to.Ptr("/path/to/template.tf"), + TemplateVersion: to.Ptr("1.0"), + }}, + {nil, nil}, + {&rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindBicep, + TemplatePath: "/path/to/template.bicep", + }, &RecipeStatus{ + TemplateKind: to.Ptr(recipes.TemplateKindBicep), + TemplatePath: to.Ptr("/path/to/template.bicep"), + TemplateVersion: nil, + }}, + } + + for _, tt := range testCases { + status := fromRecipeStatus(tt.recipeStatus) + if tt.expected == nil { + require.Nil(t, status) + } else { + require.Equal(t, *tt.expected, *status) + } + } +} + func TestToRecipeDataModel(t *testing.T) { testset := []struct { versioned *Recipe diff --git a/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion.go b/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion.go index 3f7178a214..a0acf41755 100644 --- a/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion.go +++ b/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion.go @@ -130,6 +130,7 @@ func (dst *DaprPubSubBrokerResource) ConvertFrom(src v1.DataModelInterface) erro ProvisioningState: fromProvisioningStateDataModel(daprPubSub.InternalMetadata.AsyncProvisioningState), Status: &ResourceStatus{ OutputResources: toOutputResources(daprPubSub.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(daprPubSub.Properties.Status.Recipe), }, } diff --git a/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion_test.go b/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion_test.go index 29064f6e49..543129e9a0 100644 --- a/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion_test.go +++ b/pkg/daprrp/api/v20231001preview/pubsubbroker_conversion_test.go @@ -217,7 +217,7 @@ func TestDaprPubSubBroker_ConvertDataModelToVersioned(t *testing.T) { ResourceProvisioning: to.Ptr(ResourceProvisioningRecipe), ComponentName: to.Ptr("test-dpsb"), ProvisioningState: to.Ptr(ProvisioningStateAccepted), - Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}), + Status: resourcetypeutil.MustPopulateResourceStatusWithRecipe(&ResourceStatus{}), }, Tags: map[string]*string{ "env": to.Ptr("dev"), diff --git a/pkg/daprrp/api/v20231001preview/secretstore_conversion.go b/pkg/daprrp/api/v20231001preview/secretstore_conversion.go index 5b88f12505..7b49a01559 100644 --- a/pkg/daprrp/api/v20231001preview/secretstore_conversion.go +++ b/pkg/daprrp/api/v20231001preview/secretstore_conversion.go @@ -124,6 +124,7 @@ func (dst *DaprSecretStoreResource) ConvertFrom(src v1.DataModelInterface) error ComponentName: to.Ptr(daprSecretStore.Properties.ComponentName), Status: &ResourceStatus{ OutputResources: toOutputResources(daprSecretStore.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(daprSecretStore.Properties.Status.Recipe), }, } if daprSecretStore.Properties.ResourceProvisioning == portableresources.ResourceProvisioningManual { @@ -133,5 +134,6 @@ func (dst *DaprSecretStoreResource) ConvertFrom(src v1.DataModelInterface) error } else { dst.Properties.Recipe = fromRecipeDataModel(daprSecretStore.Properties.Recipe) } + return nil } diff --git a/pkg/daprrp/api/v20231001preview/secretstore_conversion_test.go b/pkg/daprrp/api/v20231001preview/secretstore_conversion_test.go index 89ebe81a49..deb65db41e 100644 --- a/pkg/daprrp/api/v20231001preview/secretstore_conversion_test.go +++ b/pkg/daprrp/api/v20231001preview/secretstore_conversion_test.go @@ -181,7 +181,12 @@ func TestDaprSecretStore_ConvertDataModelToVersioned(t *testing.T) { Metadata: map[string]any{"foo": "bar"}, ComponentName: to.Ptr("test-dss"), ProvisioningState: to.Ptr(ProvisioningStateAccepted), - Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}), + Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{ + Recipe: &RecipeStatus{ + TemplateKind: to.Ptr("bicep"), + TemplatePath: to.Ptr("br:sampleregistry.azureacr.io/radius/recipes/abc"), + }, + }), }, Tags: map[string]*string{ "env": to.Ptr("dev"), diff --git a/pkg/daprrp/api/v20231001preview/statestore_conversion.go b/pkg/daprrp/api/v20231001preview/statestore_conversion.go index ab0129ef33..d634fe54eb 100644 --- a/pkg/daprrp/api/v20231001preview/statestore_conversion.go +++ b/pkg/daprrp/api/v20231001preview/statestore_conversion.go @@ -107,6 +107,7 @@ func (dst *DaprStateStoreResource) ConvertFrom(src v1.DataModelInterface) error dst.Properties = &DaprStateStoreProperties{ Status: &ResourceStatus{ OutputResources: toOutputResources(daprStateStore.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(daprStateStore.Properties.Status.Recipe), }, ProvisioningState: fromProvisioningStateDataModel(daprStateStore.InternalMetadata.AsyncProvisioningState), Environment: to.Ptr(daprStateStore.Properties.Environment), diff --git a/pkg/daprrp/api/v20231001preview/statestore_conversion_test.go b/pkg/daprrp/api/v20231001preview/statestore_conversion_test.go index 765cad2dd4..32d7d3b9a9 100644 --- a/pkg/daprrp/api/v20231001preview/statestore_conversion_test.go +++ b/pkg/daprrp/api/v20231001preview/statestore_conversion_test.go @@ -155,7 +155,7 @@ func TestDaprStateStore_ConvertDataModelToVersioned(t *testing.T) { Environment: to.Ptr("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0"), ComponentName: to.Ptr("stateStore0"), ProvisioningState: to.Ptr(ProvisioningStateAccepted), - Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}), + Status: resourcetypeutil.MustPopulateResourceStatusWithRecipe(&ResourceStatus{}), }, } @@ -171,11 +171,13 @@ func TestDaprStateStore_ConvertDataModelToVersioned(t *testing.T) { ID: to.Ptr("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Microsoft.Sql/servers/testServer/databases/testDatabase"), }, } + expected.Properties.Status = resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}) } else if payload == "statestore_recipe_resourcedatamodel.json" { expected.Properties.ResourceProvisioning = to.Ptr(ResourceProvisioningRecipe) expected.Properties.Recipe = &Recipe{ Name: to.Ptr("recipe-test"), } + expected.Properties.Status = resourcetypeutil.MustPopulateResourceStatusWithRecipe(&ResourceStatus{}) } require.Equal(t, expected, versionedResource) diff --git a/pkg/daprrp/api/v20231001preview/testdata/pubsubbroker_recipe_datamodel.json b/pkg/daprrp/api/v20231001preview/testdata/pubsubbroker_recipe_datamodel.json index 8292bc3900..0e1f1e1192 100644 --- a/pkg/daprrp/api/v20231001preview/testdata/pubsubbroker_recipe_datamodel.json +++ b/pkg/daprrp/api/v20231001preview/testdata/pubsubbroker_recipe_datamodel.json @@ -21,7 +21,11 @@ { "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource" } - ] + ], + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } }, "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/test-app", "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env", diff --git a/pkg/daprrp/api/v20231001preview/testdata/secretstore_recipe_resourcedatamodel.json b/pkg/daprrp/api/v20231001preview/testdata/secretstore_recipe_resourcedatamodel.json index 1758924778..822d6a96af 100644 --- a/pkg/daprrp/api/v20231001preview/testdata/secretstore_recipe_resourcedatamodel.json +++ b/pkg/daprrp/api/v20231001preview/testdata/secretstore_recipe_resourcedatamodel.json @@ -21,7 +21,11 @@ { "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource" } - ] + ], + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } }, "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env", "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/test-app", diff --git a/pkg/daprrp/api/v20231001preview/testdata/statestore_recipe_resourcedatamodel.json b/pkg/daprrp/api/v20231001preview/testdata/statestore_recipe_resourcedatamodel.json index 98889019fa..0ef9f96000 100644 --- a/pkg/daprrp/api/v20231001preview/testdata/statestore_recipe_resourcedatamodel.json +++ b/pkg/daprrp/api/v20231001preview/testdata/statestore_recipe_resourcedatamodel.json @@ -21,7 +21,11 @@ { "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource" } - ] + ], + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } }, "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", diff --git a/pkg/daprrp/api/v20231001preview/zz_generated_models.go b/pkg/daprrp/api/v20231001preview/zz_generated_models.go index fb53d52db7..b3b1af923d 100644 --- a/pkg/daprrp/api/v20231001preview/zz_generated_models.go +++ b/pkg/daprrp/api/v20231001preview/zz_generated_models.go @@ -478,6 +478,18 @@ type Recipe struct { Parameters map[string]any } +// 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. + TemplateKind *string + + // REQUIRED; TemplatePath is the path of the recipe consumed by the portable resource upon deployment. + TemplatePath *string + + // TemplateVersion is the version number of the template. + TemplateVersion *string +} + // RecipeUpdate - The recipe used to automatically deploy underlying infrastructure for a portable resource type RecipeUpdate struct { // The name of the recipe within the environment to use @@ -515,6 +527,9 @@ type ResourceStatus struct { // Properties of an output resource OutputResources []*OutputResource + + // READ-ONLY; The recipe data at the time of deployment + Recipe *RecipeStatus } // SystemData - Metadata pertaining to creation and last modification of the resource. diff --git a/pkg/daprrp/api/v20231001preview/zz_generated_models_serde.go b/pkg/daprrp/api/v20231001preview/zz_generated_models_serde.go index 3174b7bdcc..d33e1b130e 100644 --- a/pkg/daprrp/api/v20231001preview/zz_generated_models_serde.go +++ b/pkg/daprrp/api/v20231001preview/zz_generated_models_serde.go @@ -1100,6 +1100,41 @@ func (r *Recipe) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type RecipeStatus. +func (r RecipeStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "templateKind", r.TemplateKind) + populate(objectMap, "templatePath", r.TemplatePath) + populate(objectMap, "templateVersion", r.TemplateVersion) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RecipeStatus. +func (r *RecipeStatus) 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 "templateKind": + err = unpopulate(val, "TemplateKind", &r.TemplateKind) + delete(rawMsg, key) + case "templatePath": + err = unpopulate(val, "TemplatePath", &r.TemplatePath) + delete(rawMsg, key) + case "templateVersion": + err = unpopulate(val, "TemplateVersion", &r.TemplateVersion) + 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 RecipeUpdate. func (r RecipeUpdate) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -1202,6 +1237,7 @@ func (r ResourceStatus) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "compute", r.Compute) populate(objectMap, "outputResources", r.OutputResources) + populate(objectMap, "recipe", r.Recipe) return json.Marshal(objectMap) } @@ -1220,6 +1256,9 @@ func (r *ResourceStatus) UnmarshalJSON(data []byte) error { case "outputResources": err = unpopulate(val, "OutputResources", &r.OutputResources) delete(rawMsg, key) + case "recipe": + err = unpopulate(val, "Recipe", &r.Recipe) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", r, err) diff --git a/pkg/daprrp/processors/pubsubbrokers/processor.go b/pkg/daprrp/processors/pubsubbrokers/processor.go index 7f4fb7f5ae..5b90cd724f 100644 --- a/pkg/daprrp/processors/pubsubbrokers/processor.go +++ b/pkg/daprrp/processors/pubsubbrokers/processor.go @@ -43,7 +43,7 @@ type Processor struct { // Process validates resource properties, and applies output values from the recipe output. If the resource is // being provisioned manually, it creates a Dapr component in Kubernetes. func (p *Processor) Process(ctx context.Context, resource *datamodel.DaprPubSubBroker, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.Properties.Status.Recipe) validator.AddResourcesField(&resource.Properties.Resources) validator.AddComputedStringField("componentName", &resource.Properties.ComponentName, func() (string, *processors.ValidationError) { return kubernetes.NormalizeDaprResourceName(resource.Name), nil diff --git a/pkg/daprrp/processors/secretstores/processor.go b/pkg/daprrp/processors/secretstores/processor.go index 1bdefa0f20..5c6bc5b5bb 100644 --- a/pkg/daprrp/processors/secretstores/processor.go +++ b/pkg/daprrp/processors/secretstores/processor.go @@ -43,7 +43,7 @@ type Processor struct { // Process validates resource properties, and applies output values from the recipe output. If the resource is being // provisioned manually, it creates a Dapr component in Kubernetes. func (p *Processor) Process(ctx context.Context, resource *datamodel.DaprSecretStore, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.Properties.Status.Recipe) validator.AddComputedStringField("componentName", &resource.Properties.ComponentName, func() (string, *processors.ValidationError) { return kubernetes.NormalizeDaprResourceName(resource.Name), nil }) diff --git a/pkg/daprrp/processors/statestores/processor.go b/pkg/daprrp/processors/statestores/processor.go index 8cf7e4cc5b..be9e439423 100644 --- a/pkg/daprrp/processors/statestores/processor.go +++ b/pkg/daprrp/processors/statestores/processor.go @@ -43,7 +43,7 @@ type Processor struct { // Process validates resource properties, and applies output values from the recipe output. If the resource is being // provisioned manually, it creates a Dapr component in Kubernetes. func (p *Processor) Process(ctx context.Context, resource *datamodel.DaprStateStore, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.Properties.Status.Recipe) validator.AddResourcesField(&resource.Properties.Resources) validator.AddComputedStringField("componentName", &resource.Properties.ComponentName, func() (string, *processors.ValidationError) { return kubernetes.NormalizeDaprResourceName(resource.Name), nil diff --git a/pkg/datastoresrp/api/v20231001preview/datamodel_util.go b/pkg/datastoresrp/api/v20231001preview/datamodel_util.go index 0367c6b278..d7a602ffd5 100644 --- a/pkg/datastoresrp/api/v20231001preview/datamodel_util.go +++ b/pkg/datastoresrp/api/v20231001preview/datamodel_util.go @@ -98,6 +98,23 @@ func fromResourceProvisioningDataModel(provisioning portableresources.ResourcePr return &converted } +func fromRecipeStatus(recipeStatus *rpv1.RecipeStatus) *RecipeStatus { + if recipeStatus == nil { + return nil + } + + status := &RecipeStatus{ + TemplateKind: to.Ptr(recipeStatus.TemplateKind), + TemplatePath: to.Ptr(recipeStatus.TemplatePath), + } + + if recipeStatus.TemplateVersion != "" { + status.TemplateVersion = to.Ptr(recipeStatus.TemplateVersion) + } + + return status +} + func toRecipeDataModel(r *Recipe) portableresources.ResourceRecipe { if r == nil { return portableresources.ResourceRecipe{ diff --git a/pkg/datastoresrp/api/v20231001preview/datamodel_util_test.go b/pkg/datastoresrp/api/v20231001preview/datamodel_util_test.go index 8de4cca7f2..3e1188eb93 100644 --- a/pkg/datastoresrp/api/v20231001preview/datamodel_util_test.go +++ b/pkg/datastoresrp/api/v20231001preview/datamodel_util_test.go @@ -22,6 +22,8 @@ import ( v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" "github.com/radius-project/radius/pkg/portableresources" + "github.com/radius-project/radius/pkg/recipes" + rpv1 "github.com/radius-project/radius/pkg/rp/v1" "github.com/radius-project/radius/pkg/to" "github.com/stretchr/testify/require" ) @@ -211,6 +213,42 @@ func TestFromResourceProvisiongDataModel(t *testing.T) { require.Equal(t, testCase.versioned, *sc) } } + +func Test_fromRecipeStatus(t *testing.T) { + testCases := []struct { + recipeStatus *rpv1.RecipeStatus + expected *RecipeStatus + }{ + {&rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindTerraform, + TemplatePath: "/path/to/template.tf", + TemplateVersion: "1.0", + }, &RecipeStatus{ + TemplateKind: to.Ptr(recipes.TemplateKindTerraform), + TemplatePath: to.Ptr("/path/to/template.tf"), + TemplateVersion: to.Ptr("1.0"), + }}, + {nil, nil}, + {&rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindBicep, + TemplatePath: "/path/to/template.bicep", + }, &RecipeStatus{ + TemplateKind: to.Ptr(recipes.TemplateKindBicep), + TemplatePath: to.Ptr("/path/to/template.bicep"), + TemplateVersion: nil, + }}, + } + + for _, tt := range testCases { + status := fromRecipeStatus(tt.recipeStatus) + if tt.expected == nil { + require.Nil(t, status) + } else { + require.Equal(t, *tt.expected, *status) + } + } +} + func TestToRecipeDataModel(t *testing.T) { testset := []struct { versioned *Recipe diff --git a/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion.go b/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion.go index 49e838891c..7c899f22d7 100644 --- a/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion.go +++ b/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion.go @@ -99,6 +99,7 @@ func (dst *MongoDatabaseResource) ConvertFrom(src v1.DataModelInterface) error { Database: to.Ptr(mongo.Properties.Database), Status: &ResourceStatus{ OutputResources: toOutputResources(mongo.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(mongo.Properties.Status.Recipe), }, ProvisioningState: fromProvisioningStateDataModel(mongo.InternalMetadata.AsyncProvisioningState), Environment: to.Ptr(mongo.Properties.Environment), diff --git a/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion_test.go b/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion_test.go index 0debdff5d7..bfa01cef01 100644 --- a/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion_test.go +++ b/pkg/datastoresrp/api/v20231001preview/mongodatabase_conversion_test.go @@ -296,6 +296,11 @@ func TestMongoDatabase_ConvertDataModelToVersioned(t *testing.T) { Username: to.Ptr(""), Status: &ResourceStatus{ OutputResources: nil, + Recipe: &RecipeStatus{ + TemplateKind: to.Ptr("bicep"), + TemplatePath: to.Ptr("br:sampleregistry.azureacr.io/radius/recipes/abc"), + TemplateVersion: nil, + }, }, }, Tags: map[string]*string{ diff --git a/pkg/datastoresrp/api/v20231001preview/rediscache_conversion.go b/pkg/datastoresrp/api/v20231001preview/rediscache_conversion.go index ee6eed89d0..a1bdf84e78 100644 --- a/pkg/datastoresrp/api/v20231001preview/rediscache_conversion.go +++ b/pkg/datastoresrp/api/v20231001preview/rediscache_conversion.go @@ -101,6 +101,7 @@ func (dst *RedisCacheResource) ConvertFrom(src v1.DataModelInterface) error { Username: to.Ptr(redis.Properties.Username), Status: &ResourceStatus{ OutputResources: toOutputResources(redis.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(redis.Properties.Status.Recipe), }, ProvisioningState: fromProvisioningStateDataModel(redis.InternalMetadata.AsyncProvisioningState), Environment: to.Ptr(redis.Properties.Environment), diff --git a/pkg/datastoresrp/api/v20231001preview/rediscache_conversion_test.go b/pkg/datastoresrp/api/v20231001preview/rediscache_conversion_test.go index 7c7167efad..c2b2ce7376 100644 --- a/pkg/datastoresrp/api/v20231001preview/rediscache_conversion_test.go +++ b/pkg/datastoresrp/api/v20231001preview/rediscache_conversion_test.go @@ -221,7 +221,7 @@ func TestRedisCache_ConvertDataModelToVersioned(t *testing.T) { Recipe: &Recipe{Name: to.Ptr("redis-test"), Parameters: map[string]any{"port": float64(6081)}}, Username: to.Ptr(""), TLS: to.Ptr(false), - Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}), + Status: resourcetypeutil.MustPopulateResourceStatusWithRecipe(&ResourceStatus{}), }, Tags: map[string]*string{ "env": to.Ptr("dev"), diff --git a/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion.go b/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion.go index fbce82c5b8..6abebf59b1 100644 --- a/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion.go +++ b/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion.go @@ -99,6 +99,7 @@ func (dst *SQLDatabaseResource) ConvertFrom(src v1.DataModelInterface) error { Port: to.Ptr(sql.Properties.Port), Status: &ResourceStatus{ OutputResources: toOutputResources(sql.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(sql.Properties.Status.Recipe), }, ProvisioningState: fromProvisioningStateDataModel(sql.InternalMetadata.AsyncProvisioningState), Environment: to.Ptr(sql.Properties.Environment), @@ -108,6 +109,7 @@ func (dst *SQLDatabaseResource) ConvertFrom(src v1.DataModelInterface) error { if sql.Properties.ResourceProvisioning == portableresources.ResourceProvisioningRecipe { dst.Properties.Recipe = fromRecipeDataModel(sql.Properties.Recipe) } + return nil } diff --git a/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion_test.go b/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion_test.go index 10d2dd0a57..cc13cdeb41 100644 --- a/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion_test.go +++ b/pkg/datastoresrp/api/v20231001preview/sqldatabase_conversion_test.go @@ -192,7 +192,7 @@ func TestSqlDatabase_ConvertDataModelToVersioned(t *testing.T) { }, }, ProvisioningState: to.Ptr(ProvisioningStateAccepted), - Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}), + Status: resourcetypeutil.MustPopulateResourceStatusWithRecipe(&ResourceStatus{}), }, Tags: map[string]*string{ "env": to.Ptr("dev"), diff --git a/pkg/datastoresrp/api/v20231001preview/testdata/mongodatabaseresourcedatamodel_recipe.json b/pkg/datastoresrp/api/v20231001preview/testdata/mongodatabaseresourcedatamodel_recipe.json index 32701daa2c..66904776eb 100644 --- a/pkg/datastoresrp/api/v20231001preview/testdata/mongodatabaseresourcedatamodel_recipe.json +++ b/pkg/datastoresrp/api/v20231001preview/testdata/mongodatabaseresourcedatamodel_recipe.json @@ -23,6 +23,12 @@ } }, "host": "testAccount1.mongo.cosmos.azure.com", - "port": 10255 + "port": 10255, + "status": { + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } + } } } diff --git a/pkg/datastoresrp/api/v20231001preview/testdata/rediscacheresourcedatamodel_recipe_params.json b/pkg/datastoresrp/api/v20231001preview/testdata/rediscacheresourcedatamodel_recipe_params.json index 3028bfe106..d299d1b308 100644 --- a/pkg/datastoresrp/api/v20231001preview/testdata/rediscacheresourcedatamodel_recipe_params.json +++ b/pkg/datastoresrp/api/v20231001preview/testdata/rediscacheresourcedatamodel_recipe_params.json @@ -19,7 +19,11 @@ { "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource" } - ] + ], + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } }, "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", diff --git a/pkg/datastoresrp/api/v20231001preview/testdata/sqldatabase_recipe_resourcedatamodel.json b/pkg/datastoresrp/api/v20231001preview/testdata/sqldatabase_recipe_resourcedatamodel.json index e9a341e8ef..5270d1b470 100644 --- a/pkg/datastoresrp/api/v20231001preview/testdata/sqldatabase_recipe_resourcedatamodel.json +++ b/pkg/datastoresrp/api/v20231001preview/testdata/sqldatabase_recipe_resourcedatamodel.json @@ -20,7 +20,11 @@ { "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource" } - ] + ], + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } }, "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env", "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/test-app", diff --git a/pkg/datastoresrp/api/v20231001preview/zz_generated_models.go b/pkg/datastoresrp/api/v20231001preview/zz_generated_models.go index ca23ffe4f0..a33cd7fec5 100644 --- a/pkg/datastoresrp/api/v20231001preview/zz_generated_models.go +++ b/pkg/datastoresrp/api/v20231001preview/zz_generated_models.go @@ -298,6 +298,18 @@ type Recipe struct { Parameters map[string]any } +// 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. + TemplateKind *string + + // REQUIRED; TemplatePath is the path of the recipe consumed by the portable resource upon deployment. + TemplatePath *string + + // TemplateVersion is the version number of the template. + TemplateVersion *string +} + // RecipeUpdate - The recipe used to automatically deploy underlying infrastructure for a portable resource type RecipeUpdate struct { // The name of the recipe within the environment to use @@ -473,6 +485,9 @@ type ResourceStatus struct { // Properties of an output resource OutputResources []*OutputResource + + // READ-ONLY; The recipe data at the time of deployment + Recipe *RecipeStatus } // SQLDatabaseListSecretsResult - The secret values for the given SqlDatabase resource diff --git a/pkg/datastoresrp/api/v20231001preview/zz_generated_models_serde.go b/pkg/datastoresrp/api/v20231001preview/zz_generated_models_serde.go index 5cdd83d6f5..9085583ba0 100644 --- a/pkg/datastoresrp/api/v20231001preview/zz_generated_models_serde.go +++ b/pkg/datastoresrp/api/v20231001preview/zz_generated_models_serde.go @@ -712,6 +712,41 @@ func (r *Recipe) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type RecipeStatus. +func (r RecipeStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "templateKind", r.TemplateKind) + populate(objectMap, "templatePath", r.TemplatePath) + populate(objectMap, "templateVersion", r.TemplateVersion) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RecipeStatus. +func (r *RecipeStatus) 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 "templateKind": + err = unpopulate(val, "TemplateKind", &r.TemplateKind) + delete(rawMsg, key) + case "templatePath": + err = unpopulate(val, "TemplatePath", &r.TemplatePath) + delete(rawMsg, key) + case "templateVersion": + err = unpopulate(val, "TemplateVersion", &r.TemplateVersion) + 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 RecipeUpdate. func (r RecipeUpdate) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -1131,6 +1166,7 @@ func (r ResourceStatus) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "compute", r.Compute) populate(objectMap, "outputResources", r.OutputResources) + populate(objectMap, "recipe", r.Recipe) return json.Marshal(objectMap) } @@ -1149,6 +1185,9 @@ func (r *ResourceStatus) UnmarshalJSON(data []byte) error { case "outputResources": err = unpopulate(val, "OutputResources", &r.OutputResources) delete(rawMsg, key) + case "recipe": + err = unpopulate(val, "Recipe", &r.Recipe) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", r, err) diff --git a/pkg/datastoresrp/processors/mongodatabases/processor.go b/pkg/datastoresrp/processors/mongodatabases/processor.go index 3b54fbd52b..23bfa788d6 100644 --- a/pkg/datastoresrp/processors/mongodatabases/processor.go +++ b/pkg/datastoresrp/processors/mongodatabases/processor.go @@ -32,7 +32,7 @@ type Processor struct { // Process implements the processors.Processor interface for Mongo database resources. It validates Mongo database properties // and applies the values from the RecipeOutput. func (p *Processor) Process(ctx context.Context, resource *datamodel.MongoDatabase, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.Properties.Status.Recipe) validator.AddResourcesField(&resource.Properties.Resources) validator.AddRequiredStringField(renderers.Host, &resource.Properties.Host) diff --git a/pkg/datastoresrp/processors/rediscaches/processor.go b/pkg/datastoresrp/processors/rediscaches/processor.go index 94f43bfdfb..bddb0f626b 100644 --- a/pkg/datastoresrp/processors/rediscaches/processor.go +++ b/pkg/datastoresrp/processors/rediscaches/processor.go @@ -40,7 +40,7 @@ type Processor struct { // Process implements the processors.Processor interface for RedisCache resources. It validates the input parameters and computes // the connection string and connection URI for the RedisCache resource, and applies the values from the RecipeOutput. func (p *Processor) Process(ctx context.Context, resource *datamodel.RedisCache, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.Properties.Status.Recipe) validator.AddResourcesField(&resource.Properties.Resources) validator.AddRequiredStringField(renderers.Host, &resource.Properties.Host) diff --git a/pkg/datastoresrp/processors/sqldatabases/processor.go b/pkg/datastoresrp/processors/sqldatabases/processor.go index cd5e8768e4..3c83b8bc24 100644 --- a/pkg/datastoresrp/processors/sqldatabases/processor.go +++ b/pkg/datastoresrp/processors/sqldatabases/processor.go @@ -21,7 +21,7 @@ type Processor struct { // Process implements the processors.Processor interface for SQL database resources. It validates the given resource properties // and sets the computed values and secrets in the resource, and applies the values from the RecipeOutput. func (p *Processor) Process(ctx context.Context, resource *datamodel.SqlDatabase, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.Properties.Status.Recipe) validator.AddResourcesField(&resource.Properties.Resources) validator.AddRequiredStringField(renderers.DatabaseNameValue, &resource.Properties.Database) diff --git a/pkg/messagingrp/api/v20231001preview/datamodel_util.go b/pkg/messagingrp/api/v20231001preview/datamodel_util.go index 62dc748fce..180adf7ee0 100644 --- a/pkg/messagingrp/api/v20231001preview/datamodel_util.go +++ b/pkg/messagingrp/api/v20231001preview/datamodel_util.go @@ -98,6 +98,23 @@ func fromResourceProvisioningDataModel(provisioning portableresources.ResourcePr return &converted } +func fromRecipeStatus(recipeStatus *rpv1.RecipeStatus) *RecipeStatus { + if recipeStatus == nil { + return nil + } + + status := &RecipeStatus{ + TemplateKind: to.Ptr(recipeStatus.TemplateKind), + TemplatePath: to.Ptr(recipeStatus.TemplatePath), + } + + if recipeStatus.TemplateVersion != "" { + status.TemplateVersion = to.Ptr(recipeStatus.TemplateVersion) + } + + return status +} + func fromSystemDataModel(s v1.SystemData) *SystemData { return &SystemData{ CreatedBy: to.Ptr(s.CreatedBy), diff --git a/pkg/messagingrp/api/v20231001preview/datamodel_util_test.go b/pkg/messagingrp/api/v20231001preview/datamodel_util_test.go index 77a535740e..b734c4af54 100644 --- a/pkg/messagingrp/api/v20231001preview/datamodel_util_test.go +++ b/pkg/messagingrp/api/v20231001preview/datamodel_util_test.go @@ -21,6 +21,8 @@ import ( v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" "github.com/radius-project/radius/pkg/portableresources" + "github.com/radius-project/radius/pkg/recipes" + rpv1 "github.com/radius-project/radius/pkg/rp/v1" "github.com/radius-project/radius/pkg/to" "github.com/stretchr/testify/require" ) @@ -65,6 +67,41 @@ func TestFromProvisioningStateDataModel(t *testing.T) { } } +func Test_fromRecipeStatus(t *testing.T) { + testCases := []struct { + recipeStatus *rpv1.RecipeStatus + expected *RecipeStatus + }{ + {&rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindTerraform, + TemplatePath: "/path/to/template.tf", + TemplateVersion: "1.0", + }, &RecipeStatus{ + TemplateKind: to.Ptr(recipes.TemplateKindTerraform), + TemplatePath: to.Ptr("/path/to/template.tf"), + TemplateVersion: to.Ptr("1.0"), + }}, + {nil, nil}, + {&rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindBicep, + TemplatePath: "/path/to/template.bicep", + }, &RecipeStatus{ + TemplateKind: to.Ptr(recipes.TemplateKindBicep), + TemplatePath: to.Ptr("/path/to/template.bicep"), + TemplateVersion: nil, + }}, + } + + for _, tt := range testCases { + status := fromRecipeStatus(tt.recipeStatus) + if tt.expected == nil { + require.Nil(t, status) + } else { + require.Equal(t, *tt.expected, *status) + } + } +} + func TestFromSystemDataModel(t *testing.T) { systemDataTests := []v1.SystemData{ { diff --git a/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion.go b/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion.go index 5b61c0be14..8fcae61229 100644 --- a/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion.go +++ b/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion.go @@ -96,6 +96,7 @@ func (dst *RabbitMQQueueResource) ConvertFrom(src v1.DataModelInterface) error { dst.Properties = &RabbitMQQueueProperties{ Status: &ResourceStatus{ OutputResources: toOutputResources(rabbitmq.Properties.Status.OutputResources), + Recipe: fromRecipeStatus(rabbitmq.Properties.Status.Recipe), }, ProvisioningState: fromProvisioningStateDataModel(rabbitmq.InternalMetadata.AsyncProvisioningState), Environment: to.Ptr(rabbitmq.Properties.Environment), @@ -112,6 +113,7 @@ func (dst *RabbitMQQueueResource) ConvertFrom(src v1.DataModelInterface) error { if rabbitmq.Properties.ResourceProvisioning == portableresources.ResourceProvisioningRecipe { dst.Properties.Recipe = fromRecipeDataModel(rabbitmq.Properties.Recipe) } + return nil } diff --git a/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion_test.go b/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion_test.go index eea8eaae2f..d347a6be87 100644 --- a/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion_test.go +++ b/pkg/messagingrp/api/v20231001preview/rabbitmq_conversion_test.go @@ -189,7 +189,12 @@ func TestRabbitMQQueue_ConvertDataModelToVersioned(t *testing.T) { "foo": "bar", }, }, - Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}), + Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{ + Recipe: &RecipeStatus{ + TemplateKind: to.Ptr("bicep"), + TemplatePath: to.Ptr("br:sampleregistry.azureacr.io/radius/recipes/abc"), + }, + }), }, Tags: map[string]*string{ "env": to.Ptr("dev"), diff --git a/pkg/messagingrp/api/v20231001preview/testdata/rabbitmq_recipe_datamodel.json b/pkg/messagingrp/api/v20231001preview/testdata/rabbitmq_recipe_datamodel.json index 4b0e169796..9154cfb360 100644 --- a/pkg/messagingrp/api/v20231001preview/testdata/rabbitmq_recipe_datamodel.json +++ b/pkg/messagingrp/api/v20231001preview/testdata/rabbitmq_recipe_datamodel.json @@ -20,7 +20,11 @@ { "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource" } - ] + ], + "recipe": { + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc" + } }, "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env", "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/test-app", diff --git a/pkg/messagingrp/api/v20231001preview/zz_generated_models.go b/pkg/messagingrp/api/v20231001preview/zz_generated_models.go index 503caa54e9..bd71e761e8 100644 --- a/pkg/messagingrp/api/v20231001preview/zz_generated_models.go +++ b/pkg/messagingrp/api/v20231001preview/zz_generated_models.go @@ -312,6 +312,18 @@ type Recipe struct { Parameters map[string]any } +// 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. + TemplateKind *string + + // REQUIRED; TemplatePath is the path of the recipe consumed by the portable resource upon deployment. + TemplatePath *string + + // TemplateVersion is the version number of the template. + TemplateVersion *string +} + // RecipeUpdate - The recipe used to automatically deploy underlying infrastructure for a portable resource type RecipeUpdate struct { // The name of the recipe within the environment to use @@ -349,6 +361,9 @@ type ResourceStatus struct { // Properties of an output resource OutputResources []*OutputResource + + // READ-ONLY; The recipe data at the time of deployment + Recipe *RecipeStatus } // SystemData - Metadata pertaining to creation and last modification of the resource. diff --git a/pkg/messagingrp/api/v20231001preview/zz_generated_models_serde.go b/pkg/messagingrp/api/v20231001preview/zz_generated_models_serde.go index 91598316e6..da3b6a3927 100644 --- a/pkg/messagingrp/api/v20231001preview/zz_generated_models_serde.go +++ b/pkg/messagingrp/api/v20231001preview/zz_generated_models_serde.go @@ -728,6 +728,41 @@ func (r *Recipe) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type RecipeStatus. +func (r RecipeStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "templateKind", r.TemplateKind) + populate(objectMap, "templatePath", r.TemplatePath) + populate(objectMap, "templateVersion", r.TemplateVersion) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RecipeStatus. +func (r *RecipeStatus) 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 "templateKind": + err = unpopulate(val, "TemplateKind", &r.TemplateKind) + delete(rawMsg, key) + case "templatePath": + err = unpopulate(val, "TemplatePath", &r.TemplatePath) + delete(rawMsg, key) + case "templateVersion": + err = unpopulate(val, "TemplateVersion", &r.TemplateVersion) + 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 RecipeUpdate. func (r RecipeUpdate) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -830,6 +865,7 @@ func (r ResourceStatus) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "compute", r.Compute) populate(objectMap, "outputResources", r.OutputResources) + populate(objectMap, "recipe", r.Recipe) return json.Marshal(objectMap) } @@ -848,6 +884,9 @@ func (r *ResourceStatus) UnmarshalJSON(data []byte) error { case "outputResources": err = unpopulate(val, "OutputResources", &r.OutputResources) delete(rawMsg, key) + case "recipe": + err = unpopulate(val, "Recipe", &r.Recipe) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", r, err) diff --git a/pkg/messagingrp/processors/rabbitmqqueues/processor.go b/pkg/messagingrp/processors/rabbitmqqueues/processor.go index 093b50f8df..4bce4aa215 100644 --- a/pkg/messagingrp/processors/rabbitmqqueues/processor.go +++ b/pkg/messagingrp/processors/rabbitmqqueues/processor.go @@ -38,7 +38,7 @@ type Processor struct { // Process implements the processors.Processor interface for RabbitMQQueue resources. It validates the required fields // and computed secret fields of the RabbitMQQueue resource and returns an error if validation fails. func (p *Processor) Process(ctx context.Context, resource *msg_dm.RabbitMQQueue, options processors.Options) error { - validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources) + validator := processors.NewValidator(&resource.ComputedValues, &resource.SecretValues, &resource.Properties.Status.OutputResources, resource.ResourceMetadata().Status.Recipe) validator.AddResourcesField(&resource.Properties.Resources) validator.AddRequiredStringField(Queue, &resource.Properties.Queue) validator.AddRequiredStringField(renderers.Host, &resource.Properties.Host) diff --git a/pkg/portableresources/backend/controller/createorupdateresource.go b/pkg/portableresources/backend/controller/createorupdateresource.go index 15ee3d8fab..6e338356a8 100644 --- a/pkg/portableresources/backend/controller/createorupdateresource.go +++ b/pkg/portableresources/backend/controller/createorupdateresource.go @@ -76,6 +76,12 @@ func (c *CreateOrUpdateResource[P, T]) Run(ctx context.Context, req *ctrl.Reques return ctrl.Result{}, err } + // We will initialize the pointer with an empty recipe status object here and the actual value + // will be eventually populated by the processor. + if data.ResourceMetadata().Status.Recipe == nil { + data.ResourceMetadata().Status.Recipe = &rpv1.RecipeStatus{} + } + // Clone existing output resources so we can diff them later. previousOutputResources := c.copyOutputResources(data) @@ -119,10 +125,10 @@ func (c *CreateOrUpdateResource[P, T]) Run(ctx context.Context, req *ctrl.Reques return ctrl.Result{}, err } } - if recipeDataModel.Recipe() != nil { recipeDataModel.Recipe().DeploymentStatus = util.Success } + update := &store.Object{ Metadata: store.Metadata{ ID: req.ResourceID, diff --git a/pkg/portableresources/processors/validator.go b/pkg/portableresources/processors/validator.go index 668980ae54..9f1115ffa8 100644 --- a/pkg/portableresources/processors/validator.go +++ b/pkg/portableresources/processors/validator.go @@ -52,12 +52,15 @@ type Validator struct { // OutputResources stores the output resources extracted from the data model and recipe output. OutputResources *[]rpv1.OutputResource + + // Status stores the recipe status extracted from the recipe output. + Status *rpv1.RecipeStatus } // NewValidator initializes and returns a new Validator instance with empty data structures for connection values, // connection secrets and output resources. Use the parameters to pass in pointers to the corresponding fields on // the resource data model. -func NewValidator(connectionValues *map[string]any, connectionSecrets *map[string]rpv1.SecretValueReference, outputResources *[]rpv1.OutputResource) *Validator { +func NewValidator(connectionValues *map[string]any, connectionSecrets *map[string]rpv1.SecretValueReference, outputResources *[]rpv1.OutputResource, status *rpv1.RecipeStatus) *Validator { // Empty the computed data structures. This ensures that we don't accumulate data from previous validations. *connectionValues = map[string]any{} *connectionSecrets = map[string]rpv1.SecretValueReference{} @@ -67,6 +70,7 @@ func NewValidator(connectionValues *map[string]any, connectionSecrets *map[strin ConnectionValues: *connectionValues, ConnectionSecrets: *connectionSecrets, OutputResources: outputResources, + Status: status, } } @@ -160,6 +164,10 @@ func (v *Validator) SetAndValidate(output *recipes.RecipeOutput) error { } *v.OutputResources = append(*v.OutputResources, recipeResources...) + + if output.Status != nil { + *v.Status = *output.Status + } } if v.resourcesField != nil { diff --git a/pkg/portableresources/processors/validator_test.go b/pkg/portableresources/processors/validator_test.go index 3eef229781..2f2b7a360c 100644 --- a/pkg/portableresources/processors/validator_test.go +++ b/pkg/portableresources/processors/validator_test.go @@ -39,8 +39,9 @@ func Test_NewValidator(t *testing.T) { var outputResources []rpv1.OutputResource var values map[string]any var secrets map[string]rpv1.SecretValueReference + var status rpv1.RecipeStatus = rpv1.RecipeStatus{} - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) require.NotNil(t, v) require.NotNil(t, outputResources) require.NotNil(t, values) @@ -49,6 +50,7 @@ func Test_NewValidator(t *testing.T) { require.Same(t, &outputResources, v.OutputResources) require.Equal(t, values, v.ConnectionValues) require.Equal(t, secrets, v.ConnectionSecrets) + require.Equal(t, &status, v.Status) }) t.Run("provided datastores", func(t *testing.T) { @@ -57,8 +59,9 @@ func Test_NewValidator(t *testing.T) { } values := map[string]any{"test": ""} secrets := map[string]rpv1.SecretValueReference{"test": {}} + status := rpv1.RecipeStatus{} - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) require.NotNil(t, v) require.NotNil(t, outputResources) require.NotNil(t, values) @@ -79,8 +82,9 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { outputResources := []rpv1.OutputResource{} values := map[string]any{} secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) err := v.SetAndValidate(nil) require.NoError(t, err) @@ -90,10 +94,11 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { outputResources := []rpv1.OutputResource{} values := map[string]any{} secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} var resources *[]*portableresources.ResourceReference - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) v.AddResourcesField(resources) err := v.SetAndValidate(nil) @@ -105,10 +110,11 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { outputResources := []rpv1.OutputResource{} values := map[string]any{} secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} resources := []*portableresources.ResourceReference{} - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) v.AddResourcesField(&resources) err := v.SetAndValidate(nil) @@ -120,10 +126,11 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { outputResources := []rpv1.OutputResource{} values := map[string]any{} secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) - err := v.SetAndValidate(&recipes.RecipeOutput{}) + err := v.SetAndValidate(&recipes.RecipeOutput{Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Empty(t, outputResources) @@ -132,10 +139,11 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { outputResources := []rpv1.OutputResource{} values := map[string]any{} secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} resources := []*portableresources.ResourceReference{{ID: "////invalid//////"}} - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) v.AddResourcesField(&resources) err := v.SetAndValidate(nil) @@ -149,12 +157,13 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { outputResources := []rpv1.OutputResource{} values := map[string]any{} secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} output := recipes.RecipeOutput{ Resources: []string{"////invalid//////"}, } - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) err := v.SetAndValidate(&output) require.Error(t, err) @@ -166,6 +175,7 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { outputResources := []rpv1.OutputResource{} values := map[string]any{} secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} resourcesField := []*portableresources.ResourceReference{ { @@ -175,9 +185,10 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { output := recipes.RecipeOutput{ Resources: []string{"/planes/aws/aws/accounts/1234/regions/us-west-1/providers/AWS.Kinesis/Stream/my-stream2"}, + Status: &rpv1.RecipeStatus{}, } - v := NewValidator(&values, &secrets, &outputResources) + v := NewValidator(&values, &secrets, &outputResources, &status) v.AddResourcesField(&resourcesField) err := v.SetAndValidate(&output) @@ -200,7 +211,7 @@ func Test_Validator_SetAndValidate_OutputResources(t *testing.T) { func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { t.Run("existing required value preserved", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "existing", @@ -208,7 +219,7 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { v.AddRequiredStringField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "ignored"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "ignored"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "existing", model.StringField) require.Equal(t, "existing", v.ConnectionValues["test"]) @@ -216,7 +227,7 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { }) t.Run("existing required secret preserved", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "existing", @@ -224,7 +235,7 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { v.AddRequiredSecretField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "ignored"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "ignored"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "existing", model.StringField) require.Equal(t, rpv1.SecretValueReference{Value: "existing"}, v.ConnectionSecrets["test"]) @@ -232,14 +243,14 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { }) t.Run("required recipe value set", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddRequiredStringField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "new"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "new"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "new", model.StringField) require.Equal(t, "new", v.ConnectionValues["test"]) @@ -247,14 +258,14 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { }) t.Run("required recipe secret set", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddRequiredSecretField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "new"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "new"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "new", model.StringField) require.Equal(t, rpv1.SecretValueReference{Value: "new"}, v.ConnectionSecrets["test"]) @@ -262,21 +273,21 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { }) t.Run("required value missing with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddRequiredStringField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{}) + err := v.SetAndValidate(&recipes.RecipeOutput{Status: &rpv1.RecipeStatus{}}) require.Error(t, err) require.IsType(t, &ValidationError{}, err) require.Equal(t, "the connection value \"test\" should be provided by the recipe, set '.properties.test' to provide a value manually", err.Error()) }) t.Run("required value missing without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -290,21 +301,21 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { }) t.Run("required secret missing with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddRequiredSecretField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{}) + err := v.SetAndValidate(&recipes.RecipeOutput{Status: &rpv1.RecipeStatus{}}) require.Error(t, err) require.IsType(t, &ValidationError{}, err) require.Equal(t, "the connection secret \"test\" should be provided by the recipe, set '.properties.secrets.test' to provide a value manually", err.Error()) }) t.Run("required secret missing without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -320,7 +331,7 @@ func Test_Validator_SetAndValidate_Required_Strings(t *testing.T) { func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { t.Run("existing optional value preserved", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "existing", @@ -328,7 +339,7 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { v.AddOptionalStringField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "ignored"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "ignored"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "existing", model.StringField) require.Equal(t, "existing", v.ConnectionValues["test"]) @@ -336,7 +347,7 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { }) t.Run("existing optional secret preserved", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "existing", @@ -344,7 +355,7 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { v.AddOptionalSecretField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "ignored"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "ignored"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "existing", model.StringField) require.Equal(t, rpv1.SecretValueReference{Value: "existing"}, v.ConnectionSecrets["test"]) @@ -352,14 +363,14 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { }) t.Run("optional recipe value set", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddOptionalStringField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "new"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "new"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "new", model.StringField) require.Equal(t, "new", v.ConnectionValues["test"]) @@ -367,14 +378,14 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { }) t.Run("Optional recipe secret set", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddOptionalSecretField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "new"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Secrets: map[string]any{"test": "new"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "new", model.StringField) require.Equal(t, rpv1.SecretValueReference{Value: "new"}, v.ConnectionSecrets["test"]) @@ -382,14 +393,14 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { }) t.Run("optional value missing with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddOptionalStringField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{}) + err := v.SetAndValidate(&recipes.RecipeOutput{Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "", model.StringField) require.Empty(t, v.ConnectionValues) @@ -397,7 +408,7 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { }) t.Run("optional value missing without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -412,14 +423,14 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { }) t.Run("optional secret missing with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", } v.AddOptionalSecretField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{}) + err := v.SetAndValidate(&recipes.RecipeOutput{Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "", model.StringField) require.Empty(t, v.ConnectionValues) @@ -427,7 +438,7 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { }) t.Run("optional secret missing without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -445,7 +456,7 @@ func Test_Validator_SetAndValidate_Optional_Strings(t *testing.T) { func Test_Validator_SetAndValidate_Computed_Strings(t *testing.T) { // Code path for computed strings is the same as optional, except when the value is missing.\ t.Run("computed secret is computed with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -457,7 +468,7 @@ func Test_Validator_SetAndValidate_Computed_Strings(t *testing.T) { }) v.AddOptionalStringField("regular", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": "YO"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": "YO"}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, "YO", model.StringField) require.Equal(t, "YO-computed", model.AnotherCoolStringField) @@ -466,7 +477,7 @@ func Test_Validator_SetAndValidate_Computed_Strings(t *testing.T) { }) t.Run("computed secret is computed without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "YO", @@ -487,7 +498,7 @@ func Test_Validator_SetAndValidate_Computed_Strings(t *testing.T) { }) t.Run("computed secret error", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -498,14 +509,14 @@ func Test_Validator_SetAndValidate_Computed_Strings(t *testing.T) { }) v.AddOptionalStringField("regular", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": "YO"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": "YO"}, Status: &rpv1.RecipeStatus{}}) require.Error(t, err) require.IsType(t, &ValidationError{}, err) require.Equal(t, "OH NO!", err.Error()) }) t.Run("computed secret not run if regular fields error", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -527,7 +538,7 @@ func Test_Validator_SetAndValidate_Computed_Strings(t *testing.T) { func Test_Validator_SetAndValidate_Computed_Boolean(t *testing.T) { // Code path for computed booleans is the same as optional, except when the value is missing.\ t.Run("computed value is computed with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ BooleanField: false, @@ -539,14 +550,14 @@ func Test_Validator_SetAndValidate_Computed_Boolean(t *testing.T) { }) v.AddOptionalInt32Field("regular", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": 6380}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": 6380}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, true, model.BooleanField) require.Equal(t, map[string]any{"regular": int32(6380), "computed": true}, v.ConnectionValues) }) t.Run("computed value is computed without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ BooleanField: false, @@ -558,14 +569,14 @@ func Test_Validator_SetAndValidate_Computed_Boolean(t *testing.T) { }) v.AddOptionalInt32Field("regular", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": 6380}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": 6380}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, false, model.BooleanField) require.Equal(t, map[string]any{"regular": int32(6379), "computed": false}, v.ConnectionValues) }) t.Run("computed value with recipe override", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ BooleanField: false, @@ -577,7 +588,7 @@ func Test_Validator_SetAndValidate_Computed_Boolean(t *testing.T) { }) v.AddOptionalInt32Field("regular", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": 6380}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"regular": 6380}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, true, model.BooleanField) require.Equal(t, map[string]any{"regular": int32(6380), "computed": true}, v.ConnectionValues) @@ -587,7 +598,7 @@ func Test_Validator_SetAndValidate_Computed_Boolean(t *testing.T) { func Test_Validator_SetAndValidate_TypeMismatch_Strings(t *testing.T) { // Type mismatches are only possible with recipes t.Run("type mismatch with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -595,7 +606,7 @@ func Test_Validator_SetAndValidate_TypeMismatch_Strings(t *testing.T) { v.AddRequiredStringField("test", &model.StringField) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": 3}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": 3}, Status: &rpv1.RecipeStatus{}}) require.Error(t, err) require.IsType(t, &ValidationError{}, err) require.Equal(t, "the connection value \"test\" provided by the recipe is expected to be a string, got int", err.Error()) @@ -604,7 +615,7 @@ func Test_Validator_SetAndValidate_TypeMismatch_Strings(t *testing.T) { func Test_Validator_SetAndValidate_Required_Int32(t *testing.T) { t.Run("existing required value preserved", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 47, @@ -612,7 +623,7 @@ func Test_Validator_SetAndValidate_Required_Int32(t *testing.T) { v.AddRequiredInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, int32(47), model.Int32Field) require.Equal(t, int32(47), v.ConnectionValues["test"]) @@ -620,14 +631,14 @@ func Test_Validator_SetAndValidate_Required_Int32(t *testing.T) { }) t.Run("required recipe value set", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, } v.AddRequiredInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, int32(43), model.Int32Field) require.Equal(t, int32(43), v.ConnectionValues["test"]) @@ -635,21 +646,21 @@ func Test_Validator_SetAndValidate_Required_Int32(t *testing.T) { }) t.Run("required value missing with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, } v.AddRequiredInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{}) + err := v.SetAndValidate(&recipes.RecipeOutput{Status: &rpv1.RecipeStatus{}}) require.Error(t, err) require.IsType(t, &ValidationError{}, err) require.Equal(t, "the connection value \"test\" should be provided by the recipe, set '.properties.test' to provide a value manually", err.Error()) }) t.Run("required value missing without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, @@ -665,7 +676,7 @@ func Test_Validator_SetAndValidate_Required_Int32(t *testing.T) { func Test_Validator_SetAndValidate_Optional_Int32(t *testing.T) { t.Run("existing optional value preserved", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 47, @@ -673,7 +684,7 @@ func Test_Validator_SetAndValidate_Optional_Int32(t *testing.T) { v.AddOptionalInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, int32(47), model.Int32Field) require.Equal(t, int32(47), v.ConnectionValues["test"]) @@ -681,14 +692,14 @@ func Test_Validator_SetAndValidate_Optional_Int32(t *testing.T) { }) t.Run("optional recipe value set", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, } v.AddOptionalInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int32(43)}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, int32(43), model.Int32Field) require.Equal(t, int32(43), v.ConnectionValues["test"]) @@ -696,14 +707,14 @@ func Test_Validator_SetAndValidate_Optional_Int32(t *testing.T) { }) t.Run("optional value missing with recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, } v.AddOptionalInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{}) + err := v.SetAndValidate(&recipes.RecipeOutput{Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, int32(0), model.Int32Field) require.Empty(t, v.ConnectionValues) @@ -711,7 +722,7 @@ func Test_Validator_SetAndValidate_Optional_Int32(t *testing.T) { }) t.Run("optional value missing without recipe", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, @@ -728,14 +739,14 @@ func Test_Validator_SetAndValidate_Optional_Int32(t *testing.T) { func Test_Validator_TypeConversions_Int32(t *testing.T) { t.Run("conversion from int", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, } v.AddOptionalInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int(43)}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": int(43)}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, int32(43), model.Int32Field) require.Equal(t, int32(43), v.ConnectionValues["test"]) @@ -743,14 +754,14 @@ func Test_Validator_TypeConversions_Int32(t *testing.T) { }) t.Run("conversion from float64", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, } v.AddOptionalInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": float64(43.1)}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": float64(43.1)}, Status: &rpv1.RecipeStatus{}}) require.NoError(t, err) require.Equal(t, int32(43), model.Int32Field) require.Equal(t, int32(43), v.ConnectionValues["test"]) @@ -758,14 +769,14 @@ func Test_Validator_TypeConversions_Int32(t *testing.T) { }) t.Run("failed conversion", func(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ Int32Field: 0, } v.AddOptionalInt32Field("test", &model.Int32Field) - err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "heyyyyy"}}) + err := v.SetAndValidate(&recipes.RecipeOutput{Values: map[string]any{"test": "heyyyyy"}, Status: &rpv1.RecipeStatus{}}) require.Error(t, err) require.IsType(t, &ValidationError{}, err) require.Equal(t, "the connection value \"test\" provided by the recipe is expected to be a int32, got string", err.Error()) @@ -773,7 +784,7 @@ func Test_Validator_TypeConversions_Int32(t *testing.T) { } func Test_Validator_SetAndValidate_MultipleErrors(t *testing.T) { - v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}) + v := NewValidator(&map[string]any{}, &map[string]rpv1.SecretValueReference{}, &[]rpv1.OutputResource{}, &rpv1.RecipeStatus{}) model := testDatamodel{ StringField: "", @@ -787,3 +798,25 @@ func Test_Validator_SetAndValidate_MultipleErrors(t *testing.T) { require.IsType(t, &ValidationError{}, err) require.Equal(t, "validation returned multiple errors:\n\nthe connection value \"one\" must be provided when not using a recipe. Set '.properties.one' to provide a value manually\nthe connection value \"two\" must be provided when not using a recipe. Set '.properties.two' to provide a value manually", err.Error()) } + +func Test_Validator_SetAndValidate_Status(t *testing.T) { + t.Run("status", func(t *testing.T) { + outputResources := []rpv1.OutputResource{} + values := map[string]any{} + secrets := map[string]rpv1.SecretValueReference{} + status := rpv1.RecipeStatus{} + + v := NewValidator(&values, &secrets, &outputResources, &status) + recipeOutput := recipes.RecipeOutput{ + Status: &rpv1.RecipeStatus{ + TemplateKind: "terraform", + TemplateVersion: "v1", + TemplatePath: "/abc/def", + }, + } + err := v.SetAndValidate(&recipeOutput) + require.NoError(t, err) + + require.Equal(t, v.Status, recipeOutput.Status) + }) +} diff --git a/pkg/recipes/driver/bicep.go b/pkg/recipes/driver/bicep.go index 25afa8921f..5754af8efd 100644 --- a/pkg/recipes/driver/bicep.go +++ b/pkg/recipes/driver/bicep.go @@ -150,7 +150,7 @@ func (d *bicepDriver) Execute(ctx context.Context, opts ExecuteOptions) (*recipe return nil, recipes.NewRecipeError(recipes.RecipeDeploymentFailed, fmt.Sprintf("failed to deploy recipe %s of type %s", opts.BaseOptions.Recipe.Name, opts.BaseOptions.Definition.ResourceType), recipes_util.ExecutionError, recipes.GetErrorDetails(err)) } - recipeResponse, err := d.prepareRecipeResponse(resp.Properties.Outputs, resp.Properties.OutputResources) + recipeResponse, err := d.prepareRecipeResponse(opts.BaseOptions.Definition.TemplatePath, resp.Properties.Outputs, resp.Properties.OutputResources) if err != nil { return nil, recipes.NewRecipeError(recipes.InvalidRecipeOutputs, fmt.Sprintf("failed to read the recipe output %q: %s", recipes.ResultPropertyName, err.Error()), recipes_util.ExecutionError, recipes.GetErrorDetails(err)) } @@ -339,7 +339,7 @@ func newProviderConfig(resourceGroup string, envProviders coredm.Providers) clie // prepareRecipeResponse populates the recipe response from parsing the deployment output 'result' object and the // resources created by the template. -func (d *bicepDriver) prepareRecipeResponse(outputs any, resources []*armresources.ResourceReference) (*recipes.RecipeOutput, error) { +func (d *bicepDriver) prepareRecipeResponse(templatePath string, outputs any, resources []*armresources.ResourceReference) (*recipes.RecipeOutput, error) { // We populate the recipe response from the 'result' output (if set) // and the resources created by the template. // @@ -362,6 +362,11 @@ func (d *bicepDriver) prepareRecipeResponse(outputs any, resources []*armresourc } } + recipeResponse.Status = &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindBicep, + TemplatePath: templatePath, + } + // process the 'resources' created by the template for _, id := range resources { recipeResponse.Resources = append(recipeResponse.Resources, *id.ID) diff --git a/pkg/recipes/driver/bicep_test.go b/pkg/recipes/driver/bicep_test.go index ca80d6aa89..cbe9802b81 100644 --- a/pkg/recipes/driver/bicep_test.go +++ b/pkg/recipes/driver/bicep_test.go @@ -294,9 +294,24 @@ func Test_Bicep_PrepareRecipeResponse_Success(t *testing.T) { "host": "myrediscache.redis.cache.windows.net", "port": float64(6379), }, + Status: &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindBicep, + TemplatePath: "radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", + }, } - actualResponse, err := d.prepareRecipeResponse(response, resources) + opts := ExecuteOptions{ + BaseOptions: BaseOptions{ + Definition: recipes.EnvironmentDefinition{ + Name: "mongo-azure", + Driver: recipes.TemplateKindBicep, + TemplatePath: "radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", + ResourceType: "Applications.Datastores/mongoDatabases", + }, + }, + PrevState: []string{}, + } + actualResponse, err := d.prepareRecipeResponse(opts.BaseOptions.Definition.TemplatePath, response, resources) require.NoError(t, err) require.Equal(t, expectedResponse, actualResponse) } @@ -327,9 +342,13 @@ func Test_Bicep_PrepareRecipeResponse_EmptySecret(t *testing.T) { "host": "myrediscache.redis.cache.windows.net", "port": float64(6379), }, + Status: &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindBicep, + TemplatePath: "radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", + }, } - actualResponse, err := d.prepareRecipeResponse(response, resources) + actualResponse, err := d.prepareRecipeResponse("radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", response, resources) require.NoError(t, err) require.Equal(t, expectedResponse, actualResponse) } @@ -345,9 +364,13 @@ func Test_Bicep_PrepareRecipeResponse_EmptyResult(t *testing.T) { response := map[string]any{} expectedResponse := &recipes.RecipeOutput{ Resources: []string{"outputResourceId"}, + Status: &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindBicep, + TemplatePath: "radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", + }, } - actualResponse, err := d.prepareRecipeResponse(response, resources) + actualResponse, err := d.prepareRecipeResponse("radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", response, resources) require.NoError(t, err) require.Equal(t, expectedResponse, actualResponse) } diff --git a/pkg/recipes/driver/terraform.go b/pkg/recipes/driver/terraform.go index 001304316e..0db11ac009 100644 --- a/pkg/recipes/driver/terraform.go +++ b/pkg/recipes/driver/terraform.go @@ -26,6 +26,7 @@ import ( "github.com/google/uuid" v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" + rpv1 "github.com/radius-project/radius/pkg/rp/v1" "golang.org/x/exp/slices" "k8s.io/client-go/kubernetes" @@ -99,7 +100,7 @@ func (d *terraformDriver) Execute(ctx context.Context, opts ExecuteOptions) (*re return nil, recipes.NewRecipeError(recipes.RecipeDeploymentFailed, err.Error(), recipes_util.ExecutionError, recipes.GetErrorDetails(err)) } - recipeOutputs, err := d.prepareRecipeResponse(ctx, tfState) + recipeOutputs, err := d.prepareRecipeResponse(ctx, opts.BaseOptions.Definition, tfState) if err != nil { return nil, recipes.NewRecipeError(recipes.InvalidRecipeOutputs, fmt.Sprintf("failed to read the recipe output %q: %s", recipes.ResultPropertyName, err.Error()), recipes_util.ExecutionError, recipes.GetErrorDetails(err)) } @@ -136,7 +137,7 @@ func (d *terraformDriver) Delete(ctx context.Context, opts DeleteOptions) error // prepareRecipeResponse populates the recipe response from the module output named "result" and the // resources deployed by the Terraform module. The outputs and resources are retrieved from the input Terraform JSON state. -func (d *terraformDriver) prepareRecipeResponse(ctx context.Context, tfState *tfjson.State) (*recipes.RecipeOutput, error) { +func (d *terraformDriver) prepareRecipeResponse(ctx context.Context, definition recipes.EnvironmentDefinition, tfState *tfjson.State) (*recipes.RecipeOutput, error) { if tfState == nil || (*tfState == tfjson.State{}) { return &recipes.RecipeOutput{}, errors.New("terraform state is empty") } @@ -153,6 +154,12 @@ func (d *terraformDriver) prepareRecipeResponse(ctx context.Context, tfState *tf } } + recipeResponse.Status = &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindTerraform, + TemplatePath: definition.TemplatePath, + TemplateVersion: definition.TemplateVersion, + } + deployedResources, err := d.getDeployedOutputResources(ctx, tfState.Values.RootModule) if err != nil { return &recipes.RecipeOutput{}, err diff --git a/pkg/recipes/driver/terraform_test.go b/pkg/recipes/driver/terraform_test.go index ee831c24f0..3e42acdcb8 100644 --- a/pkg/recipes/driver/terraform_test.go +++ b/pkg/recipes/driver/terraform_test.go @@ -66,10 +66,11 @@ func buildTestInputs() (recipes.Configuration, recipes.ResourceMetadata, recipes } envRecipe := recipes.EnvironmentDefinition{ - Name: "redis-azure", - Driver: recipes.TemplateKindBicep, - TemplatePath: "Azure/redis/azurerm", - ResourceType: "Applications.Datastores/redisCaches", + Name: "redis-azure", + Driver: recipes.TemplateKindBicep, + TemplatePath: "Azure/redis/azurerm", + ResourceType: "Applications.Datastores/redisCaches", + TemplateVersion: "1.0", } return envConfig, recipeMetadata, envRecipe @@ -102,6 +103,11 @@ func Test_Terraform_Execute_Success(t *testing.T) { }, Secrets: map[string]any{}, Resources: []string{}, + Status: &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindTerraform, + TemplatePath: "Azure/redis/azurerm", + TemplateVersion: "1.0", + }, } expectedTFState := &tfjson.State{ @@ -245,6 +251,11 @@ func Test_Terraform_Execute_EmptyOperationID_Success(t *testing.T) { }, Secrets: map[string]any{}, Resources: []string{}, + Status: &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindTerraform, + TemplatePath: "Azure/redis/azurerm", + TemplateVersion: "1.0", + }, } expectedTFState := &tfjson.State{ @@ -586,6 +597,11 @@ func Test_Terraform_PrepareRecipeResponse(t *testing.T) { "/planes/kubernetes/local/namespaces/default/providers/core/ServiceAccount/test-service-account", "/planes/kubernetes/local/namespaces/test-namespace/providers/dapr.io/Component/test-dapr", }, + Status: &rpv1.RecipeStatus{ + TemplateKind: recipes.TemplateKindTerraform, + TemplatePath: "radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", + TemplateVersion: "1.0", + }, }, }, { @@ -741,9 +757,22 @@ func Test_Terraform_PrepareRecipeResponse(t *testing.T) { }, } + opts := ExecuteOptions{ + BaseOptions: BaseOptions{ + Definition: recipes.EnvironmentDefinition{ + Name: "mongo-azure", + Driver: recipes.TemplateKindTerraform, + TemplatePath: "radiusdev.azurecr.io/recipes/functionaltest/parameters/mongodatabases/azure:1.0", + ResourceType: "Applications.Datastores/mongoDatabases", + TemplateVersion: "1.0", + }, + }, + PrevState: []string{}, + } + for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { - recipeResponse, err := d.prepareRecipeResponse(context.Background(), tt.state) + recipeResponse, err := d.prepareRecipeResponse(context.Background(), opts.BaseOptions.Definition, tt.state) require.Equal(t, tt.expectedErr, err) require.Equal(t, tt.expectedResponse, recipeResponse) }) diff --git a/pkg/recipes/types.go b/pkg/recipes/types.go index 3f490155b8..b0cbc8c5ed 100644 --- a/pkg/recipes/types.go +++ b/pkg/recipes/types.go @@ -21,6 +21,7 @@ import ( "encoding/json" "github.com/radius-project/radius/pkg/corerp/datamodel" + rpv1 "github.com/radius-project/radius/pkg/rp/v1" ) // Configuration represents kubernetes runtime and cloud provider configuration, which is used by the driver while deploying recipes. @@ -98,6 +99,9 @@ type RecipeOutput struct { // Values represents the key/value pairs of properties of the deployed resource. Values map[string]any + + // Status represents the recipe status at deployment time of resource. + Status *rpv1.RecipeStatus } // PrepareRecipeOutput populates the recipe output from the recipe deployment output stored in the "result" object. diff --git a/pkg/recipes/types_test.go b/pkg/recipes/types_test.go index 776f1b8f7b..0535f6f060 100644 --- a/pkg/recipes/types_test.go +++ b/pkg/recipes/types_test.go @@ -19,6 +19,7 @@ package recipes import ( "testing" + rpv1 "github.com/radius-project/radius/pkg/rp/v1" "github.com/stretchr/testify/require" ) @@ -26,6 +27,7 @@ func TestRecipeOutput_PrepareRecipeResponse(t *testing.T) { tests := []struct { desc string result map[string]any + recipe rpv1.RecipeStatus expectedErr bool }{ { diff --git a/pkg/rp/v1/recipe.go b/pkg/rp/v1/recipe.go new file mode 100644 index 0000000000..1fef5f0fc4 --- /dev/null +++ b/pkg/rp/v1/recipe.go @@ -0,0 +1,29 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +// RecipeStatus defines the status of the recipe +type RecipeStatus struct { + // TemplateKind specifies the kind of template used for the recipe. + TemplateKind string `json:"templateKind,omitempty"` + + // TemplatePath specifies the path of the template used for the recipe. + TemplatePath string `json:"templatePath,omitempty"` + + // TemplateVersion specifies the version of the template used for the recipe. + TemplateVersion string `json:"templateVersion,omitempty"` +} diff --git a/pkg/rp/v1/types.go b/pkg/rp/v1/types.go index e34da0aac6..1f300e9f62 100644 --- a/pkg/rp/v1/types.go +++ b/pkg/rp/v1/types.go @@ -62,12 +62,20 @@ type ResourceStatus struct { // OutputResources represents the output resources associated with the radius resource. OutputResources []OutputResource `json:"outputResources,omitempty"` + Recipe *RecipeStatus `json:"recipe,omitempty"` } // DeepCopy copies the contents of the ResourceStatus struct from in to out. func (in *ResourceStatus) DeepCopy(out *ResourceStatus) { in.Compute = out.Compute in.OutputResources = out.OutputResources + if out.Recipe != nil { + in.Recipe = &RecipeStatus{ + TemplateKind: out.Recipe.TemplateKind, + TemplatePath: out.Recipe.TemplatePath, + TemplateVersion: out.Recipe.TemplateVersion, + } + } } // EnvironmentCompute represents the compute resource of Environment. 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 34cdaf12c1..41bced743f 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 @@ -4797,6 +4797,28 @@ "templateKind" ] }, + "RecipeStatus": { + "type": "object", + "description": "Recipe status at deployment time for a resource.", + "properties": { + "templateKind": { + "type": "string", + "description": "TemplateKind is the kind of the recipe template used by the portable resource upon deployment." + }, + "templatePath": { + "type": "string", + "description": "TemplatePath is the path of the recipe consumed by the portable resource upon deployment." + }, + "templateVersion": { + "type": "string", + "description": "TemplateVersion is the version number of the template." + } + }, + "required": [ + "templateKind", + "templatePath" + ] + }, "RecipeUpdate": { "type": "object", "description": "The recipe used to automatically deploy underlying infrastructure for a portable resource", @@ -4857,6 +4879,11 @@ "$ref": "#/definitions/EnvironmentCompute", "description": "The compute resource associated with the resource." }, + "recipe": { + "$ref": "#/definitions/RecipeStatus", + "description": "The recipe data at the time of deployment", + "readOnly": true + }, "outputResources": { "type": "array", "description": "Properties of an output resource", diff --git a/swagger/specification/applications/resource-manager/Applications.Dapr/preview/2023-10-01-preview/openapi.json b/swagger/specification/applications/resource-manager/Applications.Dapr/preview/2023-10-01-preview/openapi.json index 69eeb0d50f..7a54909a63 100644 --- a/swagger/specification/applications/resource-manager/Applications.Dapr/preview/2023-10-01-preview/openapi.json +++ b/swagger/specification/applications/resource-manager/Applications.Dapr/preview/2023-10-01-preview/openapi.json @@ -1596,6 +1596,28 @@ "name" ] }, + "RecipeStatus": { + "type": "object", + "description": "Recipe status at deployment time for a resource.", + "properties": { + "templateKind": { + "type": "string", + "description": "TemplateKind is the kind of the recipe template used by the portable resource upon deployment." + }, + "templatePath": { + "type": "string", + "description": "TemplatePath is the path of the recipe consumed by the portable resource upon deployment." + }, + "templateVersion": { + "type": "string", + "description": "TemplateVersion is the version number of the template." + } + }, + "required": [ + "templateKind", + "templatePath" + ] + }, "RecipeUpdate": { "type": "object", "description": "The recipe used to automatically deploy underlying infrastructure for a portable resource", @@ -1656,6 +1678,11 @@ "$ref": "#/definitions/EnvironmentCompute", "description": "The compute resource associated with the resource." }, + "recipe": { + "$ref": "#/definitions/RecipeStatus", + "description": "The recipe data at the time of deployment", + "readOnly": true + }, "outputResources": { "type": "array", "description": "Properties of an output resource", diff --git a/swagger/specification/applications/resource-manager/Applications.Datastores/preview/2023-10-01-preview/openapi.json b/swagger/specification/applications/resource-manager/Applications.Datastores/preview/2023-10-01-preview/openapi.json index 1dc9632980..b978c70260 100644 --- a/swagger/specification/applications/resource-manager/Applications.Datastores/preview/2023-10-01-preview/openapi.json +++ b/swagger/specification/applications/resource-manager/Applications.Datastores/preview/2023-10-01-preview/openapi.json @@ -1487,6 +1487,28 @@ "name" ] }, + "RecipeStatus": { + "type": "object", + "description": "Recipe status at deployment time for a resource.", + "properties": { + "templateKind": { + "type": "string", + "description": "TemplateKind is the kind of the recipe template used by the portable resource upon deployment." + }, + "templatePath": { + "type": "string", + "description": "TemplatePath is the path of the recipe consumed by the portable resource upon deployment." + }, + "templateVersion": { + "type": "string", + "description": "TemplateVersion is the version number of the template." + } + }, + "required": [ + "templateKind", + "templatePath" + ] + }, "RecipeUpdate": { "type": "object", "description": "The recipe used to automatically deploy underlying infrastructure for a portable resource", @@ -1754,6 +1776,11 @@ "$ref": "#/definitions/EnvironmentCompute", "description": "The compute resource associated with the resource." }, + "recipe": { + "$ref": "#/definitions/RecipeStatus", + "description": "The recipe data at the time of deployment", + "readOnly": true + }, "outputResources": { "type": "array", "description": "Properties of an output resource", diff --git a/swagger/specification/applications/resource-manager/Applications.Messaging/preview/2023-10-01-preview/openapi.json b/swagger/specification/applications/resource-manager/Applications.Messaging/preview/2023-10-01-preview/openapi.json index c8fea81d01..3df34aaa59 100644 --- a/swagger/specification/applications/resource-manager/Applications.Messaging/preview/2023-10-01-preview/openapi.json +++ b/swagger/specification/applications/resource-manager/Applications.Messaging/preview/2023-10-01-preview/openapi.json @@ -814,6 +814,28 @@ "name" ] }, + "RecipeStatus": { + "type": "object", + "description": "Recipe status at deployment time for a resource.", + "properties": { + "templateKind": { + "type": "string", + "description": "TemplateKind is the kind of the recipe template used by the portable resource upon deployment." + }, + "templatePath": { + "type": "string", + "description": "TemplatePath is the path of the recipe consumed by the portable resource upon deployment." + }, + "templateVersion": { + "type": "string", + "description": "TemplateVersion is the version number of the template." + } + }, + "required": [ + "templateKind", + "templatePath" + ] + }, "RecipeUpdate": { "type": "object", "description": "The recipe used to automatically deploy underlying infrastructure for a portable resource", @@ -874,6 +896,11 @@ "$ref": "#/definitions/EnvironmentCompute", "description": "The compute resource associated with the resource." }, + "recipe": { + "$ref": "#/definitions/RecipeStatus", + "description": "The recipe data at the time of deployment", + "readOnly": true + }, "outputResources": { "type": "array", "description": "Properties of an output resource", diff --git a/test/functional/datastoresrp/resources/redis_test.go b/test/functional/datastoresrp/resources/redis_test.go index 7dd32a8ca6..6bf98383a9 100644 --- a/test/functional/datastoresrp/resources/redis_test.go +++ b/test/functional/datastoresrp/resources/redis_test.go @@ -17,12 +17,15 @@ limitations under the License. package resource_test import ( + "context" + "strings" "testing" "github.com/radius-project/radius/test/functional" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/validation" + "github.com/stretchr/testify/require" ) func Test_Redis_Manual(t *testing.T) { @@ -101,6 +104,16 @@ func Test_Redis_Recipe(t *testing.T) { }, }, SkipObjectValidation: true, + PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + redis, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Datastores/redisCaches", "rds-recipe") + require.NoError(t, err) + require.NotNil(t, redis) + status := redis.Properties["status"].(map[string]any) + recipe := status["recipe"].(map[string]interface{}) + require.Equal(t, "bicep", recipe["templateKind"].(string)) + templatePath := strings.Split(recipe["templatePath"].(string), ":")[0] + require.Equal(t, "ghcr.io/radius-project/dev/test/functional/shared/recipes/redis-recipe-value-backed", templatePath) + }, }, }) diff --git a/test/functional/shared/resources/recipe_terraform_test.go b/test/functional/shared/resources/recipe_terraform_test.go index 9cfac5845a..70154ae9e7 100644 --- a/test/functional/shared/resources/recipe_terraform_test.go +++ b/test/functional/shared/resources/recipe_terraform_test.go @@ -108,6 +108,17 @@ func Test_TerraformRecipe_KubernetesRedis(t *testing.T) { require.NoError(t, err) require.Equal(t, secretNamespace, secret.Namespace) require.Equal(t, secretPrefix+secretSuffix, secret.Name) + + redis, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Core/extenders", name) + require.NoError(t, err) + require.NotNil(t, redis) + status := redis.Properties["status"].(map[string]any) + recipe := status["recipe"].(map[string]interface{}) + require.Equal(t, "terraform", recipe["templateKind"].(string)) + expectedTemplatePath := strings.Replace(functional.GetTerraformRecipeModuleServerURL()+"/kubernetes-redis.zip", "moduleServer=", "", 1) + require.Equal(t, expectedTemplatePath, recipe["templatePath"].(string)) + // At present, it is not possible to verify the template version in functional tests + // This is verified by UTs though }, }, }) diff --git a/test/testutil/resourcetypeutil/types.go b/test/testutil/resourcetypeutil/types.go index a0f3776312..b7d24a24cc 100644 --- a/test/testutil/resourcetypeutil/types.go +++ b/test/testutil/resourcetypeutil/types.go @@ -75,3 +75,35 @@ func MustPopulateResourceStatus[T any](obj T) T { return obj } + +// MustPopulateResourceStatusWithRecipe populates a ResourceStatus object with an output resource commonly used in our +// test fixtures for recipes. +// +// Example usage (in a converter test): +// +// ..ResourceStatus: resourcetypeutil.MustPopulateResourceStatusWithRecipe(&myapiversion.ResourceStatus{}) +func MustPopulateResourceStatusWithRecipe[T any](obj T) T { + data := map[string]any{ + "outputResources": []map[string]any{ + { + "id": "/planes/test/local/providers/Test.Namespace/testResources/test-resource", + }, + }, + "recipe": map[string]string{ + "templateKind": "bicep", + "templatePath": "br:sampleregistry.azureacr.io/radius/recipes/abc", + }, + } + + b, err := json.Marshal(data) + if err != nil { + panic(err) + } + + err = json.Unmarshal(b, obj) + if err != nil { + panic(err) + } + + return obj +} diff --git a/test/validation/shared.go b/test/validation/shared.go index 768be879c0..d1694b548a 100644 --- a/test/validation/shared.go +++ b/test/validation/shared.go @@ -142,13 +142,14 @@ func ValidateRPResources(ctx context.Context, t *testing.T, expected *RPResource // Validate expected output resources are present in the response if len(expectedResource.OutputResources) > 0 { t.Log("validating output resources") - bytes, err := json.Marshal(res.Properties["status"]) + status := res.Properties["status"].(map[string]interface{}) + or := status["outputResources"].([]interface{}) + bytes, err := json.Marshal(or) require.NoError(t, err) - var outputResourcesMap map[string][]OutputResourceResponse - err = json.Unmarshal(bytes, &outputResourcesMap) + var outputResources []OutputResourceResponse + err = json.Unmarshal(bytes, &outputResources) require.NoError(t, err) - outputResources := outputResourcesMap["outputResources"] for _, outputResource := range outputResources { t.Logf("Found output resource: %+v", outputResource) } diff --git a/typespec/radius/v1/resources.tsp b/typespec/radius/v1/resources.tsp index 0d9f1e9812..4c90162e1c 100644 --- a/typespec/radius/v1/resources.tsp +++ b/typespec/radius/v1/resources.tsp @@ -102,11 +102,27 @@ model KubernetesCompute extends EnvironmentCompute { `namespace`: string; } +@doc("Recipe status at deployment time for a resource.") +model RecipeStatus { + @doc("TemplateKind is the kind of the recipe template used by the portable resource upon deployment.") + templateKind: string; + + @doc("TemplatePath is the path of the recipe consumed by the portable resource upon deployment.") + templatePath: string; + + @doc("TemplateVersion is the version number of the template.") + templateVersion?: string; +} + @doc("Status of a resource.") model ResourceStatus { @doc("The compute resource associated with the resource.") compute?: EnvironmentCompute; + @doc("The recipe data at the time of deployment") + @visibility("read") + recipe?: RecipeStatus; + @doc("Properties of an output resource") @extension("x-ms-identifiers", []) outputResources?: OutputResource[];