Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add schema support for cosmos db #4780

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cli/azd/internal/cmd/add/add_configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ func Configure(
case project.ResourceTypeDbPostgres,
project.ResourceTypeDbMongo:
return fillDatabaseName(ctx, r, console, p)
case project.ResourceTypeDbCosmos:
r, err := fillDatabaseName(ctx, r, console, p)
if err != nil {
return nil, err
}
r.Props = project.CosmosDBProps{}
return r, nil
case project.ResourceTypeMessagingEventHubs:
return fillEventHubs(ctx, r, console, p)
case project.ResourceTypeMessagingServiceBus:
Expand Down
5 changes: 5 additions & 0 deletions cli/azd/internal/cmd/add/add_preview.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ func Metadata(r *project.ResourceConfig) resourceMeta {
res.UseEnvVars = []string{
"AZURE_OPENAI_ENDPOINT",
}
case project.ResourceTypeDbCosmos:
res.AzureResourceType = "Microsoft.DocumentDB/databaseAccounts"
res.UseEnvVars = []string{
"AZURE_COSMOS_ENDPOINT",
}
case project.ResourceTypeMessagingEventHubs:
res.AzureResourceType = "Microsoft.EventHub/namespaces"
res.UseEnvVars = []string{
Expand Down
21 changes: 21 additions & 0 deletions cli/azd/internal/scaffold/scaffold_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ func TestExecInfra(t *testing.T) {
DbCosmosMongo: &DatabaseCosmosMongo{
DatabaseName: "appdb",
},
DbCosmos: &DatabaseCosmos{
DatabaseName: "cosmos",
},
DbRedis: &DatabaseRedis{},
ServiceBus: &ServiceBus{},
EventHubs: &EventHubs{},
Expand All @@ -113,6 +116,9 @@ func TestExecInfra(t *testing.T) {
DbPostgres: &DatabaseReference{
DatabaseName: "appdb",
},
DbCosmos: &DatabaseReference{
DatabaseName: "cosmos",
},
ServiceBus: &ServiceBus{},
EventHubs: &EventHubs{},
StorageAccount: &StorageReference{},
Expand Down Expand Up @@ -181,6 +187,21 @@ func TestExecInfra(t *testing.T) {
},
},
},
{
"API with Cosmos",
InfraSpec{
DbCosmos: &DatabaseCosmos{},
Services: []ServiceSpec{
{
Name: "api",
Port: 3100,
DbCosmos: &DatabaseReference{
DatabaseName: "cosmos",
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
12 changes: 12 additions & 0 deletions cli/azd/internal/scaffold/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type InfraSpec struct {
// Databases to create
DbPostgres *DatabasePostgres
DbCosmosMongo *DatabaseCosmosMongo
DbCosmos *DatabaseCosmos
DbRedis *DatabaseRedis

// Messaging services
Expand Down Expand Up @@ -44,6 +45,16 @@ type DatabaseCosmosMongo struct {
DatabaseName string
}

type DatabaseCosmos struct {
DatabaseName string
Containers []CosmosSqlDatabaseContainer
}

type CosmosSqlDatabaseContainer struct {
ContainerName string
PartitionKeyPaths []string
}

type DatabaseRedis struct {
}

Expand Down Expand Up @@ -89,6 +100,7 @@ type ServiceSpec struct {
// Connection to a database
DbPostgres *DatabaseReference
DbCosmosMongo *DatabaseReference
DbCosmos *DatabaseReference
DbRedis *DatabaseReference

StorageAccount *StorageReference
Expand Down
21 changes: 21 additions & 0 deletions cli/azd/pkg/project/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func AllResourceTypes() []ResourceType {
ResourceTypeDbRedis,
ResourceTypeDbPostgres,
ResourceTypeDbMongo,
ResourceTypeDbCosmos,
ResourceTypeHostContainerApp,
ResourceTypeOpenAiModel,
ResourceTypeMessagingEventHubs,
Expand All @@ -28,6 +29,7 @@ const (
ResourceTypeDbRedis ResourceType = "db.redis"
ResourceTypeDbPostgres ResourceType = "db.postgres"
ResourceTypeDbMongo ResourceType = "db.mongo"
ResourceTypeDbCosmos ResourceType = "db.cosmos"
ResourceTypeHostContainerApp ResourceType = "host.containerapp"
ResourceTypeOpenAiModel ResourceType = "ai.openai.model"
ResourceTypeMessagingEventHubs ResourceType = "messaging.eventhubs"
Expand All @@ -43,6 +45,8 @@ func (r ResourceType) String() string {
return "PostgreSQL"
case ResourceTypeDbMongo:
return "MongoDB"
case ResourceTypeDbCosmos:
return "CosmosDB"
case ResourceTypeHostContainerApp:
return "Container App"
case ResourceTypeOpenAiModel:
Expand Down Expand Up @@ -96,6 +100,8 @@ func (r *ResourceConfig) MarshalYAML() (interface{}, error) {
errMarshal = marshalRawProps(raw.Props.(AIModelProps))
case ResourceTypeHostContainerApp:
errMarshal = marshalRawProps(raw.Props.(ContainerAppProps))
case ResourceTypeDbCosmos:
errMarshal = marshalRawProps(raw.Props.(CosmosDBProps))
case ResourceTypeMessagingEventHubs:
errMarshal = marshalRawProps(raw.Props.(EventHubsProps))
case ResourceTypeMessagingServiceBus:
Expand Down Expand Up @@ -145,6 +151,12 @@ func (r *ResourceConfig) UnmarshalYAML(value *yaml.Node) error {
return err
}
raw.Props = cap
case ResourceTypeDbCosmos:
cdp := CosmosDBProps{}
if err := unmarshalProps(&cdp); err != nil {
return err
}
raw.Props = cdp
case ResourceTypeMessagingEventHubs:
ehp := EventHubsProps{}
if err := unmarshalProps(&ehp); err != nil {
Expand Down Expand Up @@ -191,6 +203,15 @@ type AIModelPropsModel struct {
Version string `yaml:"version,omitempty"`
}

type CosmosDBProps struct {
Containers []CosmosDBContainerProps `yaml:"containers,omitempty"`
}

type CosmosDBContainerProps struct {
Name string `yaml:"containerName,omitempty"`
PartitionKeys []string `yaml:"partitionKeyPaths,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the YAML schema, does name and partitionKeys feel nicer?

}

type ServiceBusProps struct {
Queues []string `yaml:"queues,omitempty"`
Topics []string `yaml:"topics,omitempty"`
Expand Down
15 changes: 15 additions & 0 deletions cli/azd/pkg/project/scaffold_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,19 @@ func infraSpec(projectConfig *ProjectConfig) (*scaffold.InfraSpec, error) {
infraSpec.DbCosmosMongo = &scaffold.DatabaseCosmosMongo{
DatabaseName: res.Name,
}
case ResourceTypeDbCosmos:
props := res.Props.(CosmosDBProps)
containers := make([]scaffold.CosmosSqlDatabaseContainer, 0)
for _, c := range props.Containers {
containers = append(containers, scaffold.CosmosSqlDatabaseContainer{
ContainerName: c.Name,
PartitionKeyPaths: c.PartitionKeys,
})
}
infraSpec.DbCosmos = &scaffold.DatabaseCosmos{
DatabaseName: res.Name,
Containers: containers,
}
case ResourceTypeDbPostgres:
infraSpec.DbPostgres = &scaffold.DatabasePostgres{
DatabaseName: res.Name,
Expand Down Expand Up @@ -285,6 +298,8 @@ func mapHostUses(
switch useRes.Type {
case ResourceTypeDbMongo:
svcSpec.DbCosmosMongo = &scaffold.DatabaseReference{DatabaseName: useRes.Name}
case ResourceTypeDbCosmos:
svcSpec.DbCosmos = &scaffold.DatabaseReference{DatabaseName: useRes.Name}
case ResourceTypeDbPostgres:
svcSpec.DbPostgres = &scaffold.DatabaseReference{DatabaseName: useRes.Name}
case ResourceTypeDbRedis:
Expand Down
3 changes: 3 additions & 0 deletions cli/azd/resources/scaffold/templates/main.bicept
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ output AZURE_RESOURCE_REDIS_ID string = resources.outputs.AZURE_RESOURCE_REDIS_I
{{- if .DbPostgres}}
output AZURE_RESOURCE_{{alphaSnakeUpper .DbPostgres.DatabaseName}}_ID string = resources.outputs.AZURE_RESOURCE_{{alphaSnakeUpper .DbPostgres.DatabaseName}}_ID
{{- end}}
{{- if .DbCosmos }}
output AZURE_RESOURCE_{{alphaSnakeUpper .DbCosmos.DatabaseName}}_ID string = resources.outputs.AZURE_RESOURCE_{{alphaSnakeUpper .DbCosmos.DatabaseName}}_ID
{{- end}}
{{- if .StorageAccount }}
output AZURE_RESOURCE_STORAGE_ID string = resources.outputs.AZURE_RESOURCE_STORAGE_ID
{{- end}}
Expand Down
67 changes: 64 additions & 3 deletions cli/azd/resources/scaffold/templates/resources.bicept
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.4.5
{{- end}}

{{- if .DbCosmosMongo}}
module cosmos 'br/public:avm/res/document-db/database-account:0.8.1' = {
name: 'cosmos'
module cosmosMongo 'br/public:avm/res/document-db/database-account:0.8.1' = {
name: 'cosmosMongo'
params: {
name: '${abbrs.documentDBDatabaseAccounts}${resourceToken}'
location: location
Expand Down Expand Up @@ -101,6 +101,58 @@ module cosmos 'br/public:avm/res/document-db/database-account:0.8.1' = {
}
{{- end}}

{{- if .DbCosmos }}
module cosmos 'br/public:avm/res/document-db/database-account:0.8.1' = {
name: 'cosmos'
params: {
name: '${abbrs.documentDBDatabaseAccounts}${resourceToken}'
weikanglim marked this conversation as resolved.
Show resolved Hide resolved
tags: tags
location: location
locations: [
{
failoverPriority: 0
isZoneRedundant: false
locationName: location
}
]
networkRestrictions: {
ipRules: []
virtualNetworkRules: []
publicNetworkAccess: 'Enabled'
}
sqlDatabases: [
{
name: '{{ .DbCosmos.DatabaseName }}'
containers: [
{{- range .DbCosmos.Containers}}
{
name: '{{ .ContainerName }}'
paths: [
{{- range $path := .PartitionKeyPaths}}
'{{ $path }}'
{{- end}}
]
}
{{- end}}
]
Comment on lines +126 to +137
Copy link
Contributor

@weikanglim weikanglim Feb 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had time to look into this more, and I'm wondering if we should not specify any container properties. For non-Java languages, this is usually created as a dataplane operation within the SDK clients.

I think there's a similar concept in Azure Spring Cloud for CosmosDB, where the annotation would create the container on boot time. Would you be able to confirm and see if we can avoid adding this entirely?

}
]
sqlRoleAssignmentsPrincipalIds: [
weikanglim marked this conversation as resolved.
Show resolved Hide resolved
{{- range .Services}}
{{bicepName .Name}}Identity.outputs.principalId
{{- end}}
weikanglim marked this conversation as resolved.
Show resolved Hide resolved
principalId
]
sqlRoleDefinitions: [
{
name: 'service-access-cosmos-sql-role'
}
]
capabilitiesToAdd: [ 'EnableServerless' ]
}
}
{{- end}}

{{- if .DbPostgres}}
var databaseName = '{{ .DbPostgres.DatabaseName }}'
var databaseUser = 'psqladmin'
Expand Down Expand Up @@ -353,7 +405,7 @@ module {{bicepName .Name}} 'br/public:avm/res/app/container-app:0.8.0' = {
{
name: 'mongodb-url'
identity:{{bicepName .Name}}Identity.outputs.resourceId
keyVaultUrl: cosmos.outputs.exportedSecrets['MONGODB-URL'].secretUri
keyVaultUrl: cosmosMongo.outputs.exportedSecrets['MONGODB-URL'].secretUri
}
{{- end}}
{{- if .DbPostgres}}
Expand Down Expand Up @@ -407,6 +459,12 @@ module {{bicepName .Name}} 'br/public:avm/res/app/container-app:0.8.0' = {
secretRef: 'mongodb-url'
}
{{- end}}
{{- if .DbCosmos}}
{
name: 'AZURE_COSMOS_ENDPOINT'
value: cosmos.outputs.endpoint
}
{{- end}}
{{- if .DbPostgres}}
{
name: 'POSTGRES_HOST'
Expand Down Expand Up @@ -606,6 +664,9 @@ output AZURE_RESOURCE_REDIS_ID string = redis.outputs.resourceId
{{- if .DbPostgres}}
output AZURE_RESOURCE_{{alphaSnakeUpper .DbPostgres.DatabaseName}}_ID string = '${postgreServer.outputs.resourceId}/databases/{{.DbPostgres.DatabaseName}}'
{{- end}}
{{- if .DbCosmos }}
output AZURE_RESOURCE_{{alphaSnakeUpper .DbCosmos.DatabaseName}}_ID string = cosmos.outputs.resourceId
{{- end}}
{{- if .StorageAccount }}
output AZURE_RESOURCE_STORAGE_ID string = storageAccount.outputs.resourceId
{{- end}}
Expand Down
35 changes: 35 additions & 0 deletions schemas/alpha/azure.yaml.json
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@
"db.postgres",
"db.redis",
"db.mongo",
"db.cosmos",
"ai.openai.model",
"host.containerapp",
"messaging.eventhubs",
Expand All @@ -390,6 +391,7 @@
{ "if": { "properties": { "type": { "const": "db.postgres" }}}, "then": { "$ref": "#/definitions/resource"} },
{ "if": { "properties": { "type": { "const": "db.redis" }}}, "then": { "$ref": "#/definitions/resource"} },
{ "if": { "properties": { "type": { "const": "db.mongo" }}}, "then": { "$ref": "#/definitions/resource"} },
{ "if": { "properties": { "type": { "const": "db.cosmos" }}}, "then": { "$ref": "#/definitions/cosmosDbResource"} },
{ "if": { "properties": { "type": { "const": "messaging.eventhubs" }}}, "then": { "$ref": "#/definitions/eventHubsResource" } },
{ "if": { "properties": { "type": { "const": "messaging.servicebus" }}}, "then": { "$ref": "#/definitions/serviceBusResource" } },
{ "if": { "properties": { "type": { "const": "storage" }}}, "then": { "$ref": "#/definitions/storageAccountResource"} }
Expand Down Expand Up @@ -1321,6 +1323,39 @@
}
}
},
"cosmosDbResource": {
"type": "object",
"description": "A deployed, ready-to-use Azure Cosmos DB for NoSQL.",
"additionalProperties": false,
"properties": {
"type": true,
"uses": true,
"containers": {
"type": "array",
"title": "Azure Cosmos DB Containers",
"description": "A list of containers in the Azure CosmosDB.",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"containerName": {
"type": "string",
"title": "Container Name",
"description": "The name of the container."
},
"partitionKeyPaths": {
"type": "array",
"title": "Partition Key Paths",
"description": "A list of partition key paths for the container.",
"items": {
"type": "string"
}
}
}
}
}
}
},
"eventHubsResource": {
"type": "object",
"description": "An Azure Event Hubs namespace.",
Expand Down
Loading