I currently have one large .bicep file called main.bicep that I am working on modularizing. Specifically I have been working on moving the Cosmos resources into a file of its own called cosmos-db.bicep and consuming it in main.bicep.
cosmos-db.bicep
// Parameters
param cosmosAccountName string
param databaseName string
param location string = resourceGroup().location
param appTags object
param subnetFunctionName string
param ipRules array
param vnetName string
param cosmosDbName string
// Variables
var dealDataContainerName = 'deal'
var refDataContainerName = 'refdata'
var userProfileContainerName = 'userprofile'
// Cosmos DB Container info to be looped over
var cosmosContainers = [
{
name: userProfileContainerName
id: 'userprofile'
partitionKey: '/userId'
}
{
name: refDataContainerName
id: 'refdata'
partitionKey: '/partKey'
}
{
name: dealDataContainerName
id: 'deal'
partitionKey: '/dealId'
}
]
// Resource References
resource subnetFunction 'Microsoft.Network/virtualNetworks/subnets@2020-08-01' existing = {
name: subnetFunctionName
}
resource virtualNetwork 'Microsoft.Network/virtualNetworks@2020-08-01' existing = {
name: vnetName
}
// Resources
// Cosmos DB Account
resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2020-06-01-preview' = {
name: cosmosAccountName
location: location
tags: appTags
kind: 'GlobalDocumentDB'
identity: {
type: 'None'
}
properties: {
publicNetworkAccess: 'Enabled' //TODO - ulp.
enableAutomaticFailover: true
enableMultipleWriteLocations: true
isVirtualNetworkFilterEnabled: true // Suggested to be set as false by MS
virtualNetworkRules: [
{
id: subnetFunction.id
ignoreMissingVNetServiceEndpoint: false
}
]
disableKeyBasedMetadataWriteAccess: false
enableFreeTier: false
enableAnalyticalStorage: false
createMode: 'Default'
databaseAccountOfferType: 'Standard'
consistencyPolicy: {
defaultConsistencyLevel: 'Session'
maxIntervalInSeconds: 5
maxStalenessPrefix: 100
}
locations: [
{
locationName: location
failoverPriority: 0
isZoneRedundant: true
}
{
locationName: 'Central US'
failoverPriority: 1
isZoneRedundant: true
}
]
cors: []
capabilities: []
ipRules: ipRules
backupPolicy: {
type: 'Periodic'
periodicModeProperties: {
backupIntervalInMinutes: 240
backupRetentionIntervalInHours: 8
}
}
}
dependsOn: [
virtualNetwork
]
}
// Cosmos SQL Database
resource cosmosdb 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2020-04-01' = {
name: cosmosDbName
// parent: cosmos
properties: {
resource: {
id: databaseName
}
options: {
throughput: 400
}
}
}
// Cosmos Containers
resource cosmosContainerUser 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2021-06-15' = [for container in cosmosContainers: {
name: container.name
parent: cosmosdb
properties: {
resource: {
id: container.id
indexingPolicy: {
indexingMode: 'consistent'
automatic: true
includedPaths:[
{
path: '/*'
}
]
excludedPaths: [
{
path: '/"_etag"/?'
}
]
}
partitionKey: {
kind: 'Hash'
paths: [
container.partitionKey
]
}
conflictResolutionPolicy: {
mode: 'LastWriterWins'
conflictResolutionPath: '/_ts'
}
}
}
}]
output resource object = cosmos
main.bicep
module cosmos '../../../cicd/bicep/modules/datastore/cosmos-db.bicep' = {
name: cosmosAccountName
params: {
cosmosAccountName: cosmosAccountName
cosmosDbName: cosmosDbName
databaseName: databaseName
appTags: appTags
subnetFunctionName: '${virtualNetwork.name}/function'
vnetName: vnetName
ipRules: [for address in ipaddresses: {
ipAddressOrRange: '${address.CIDR}'
}]
}
}
This code works and creates a Cosmos account, one Cosmos database, and three Cosmos containers. Although the Cosmos deployments pass, the overall pipeline fails because of my key vault secret resource.
main.bicep
// Key Vault Secret
resource kvsecret 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = if (deployDB || deployKV) {
name: '${keyVault.name}/databaseConnectionString'
dependsOn: [
keyVault
]
properties: {
value: listConnectionStrings(cosmos.id, cosmos.apiVersion).connectionStrings[0].connectionString
attributes: {
nbf: 1617093384
enabled: true
exp: 1680161784
}
}
}
I get an error from the listConnectionString()
function saying: The type "module" does not contain property "apiVersion". Available properties include "name", "outputs".
In an attempt to get rid of this error I tried to change the values to listConnectionString(cosmos.name, '2020-06-01-preview')
which gives an error saying:
"The api-version '2020-06-01-preview' is invalid. The supported versions are '2021-04-01,2021-01-01,2020-10-01,2020-09-01,2020-08-01,2020-07-01,2020-06-01,2020-05-01,2020-01-01,2019-11-01,2019-10-01,2019-09-01,2019-08-01,2019-07-01,2019-06-01,2019-05-10,2019-05-01,2019-03-01,2018-11-01,2018-09-01,2018-08-01,2018-07-01,2018-06-01,2018-05-01,2018-02-01,2018-01-01,2017-08-01,2017-06-01,2017-05-10,2017-05-01,2017-03-01,2016-09-01,2016-07-01,2016-06-01,2016-02-01,2015-11-01,2015-01-01,2014-04-01-preview,2014-04-01,2014-01-01,2013-03-01,2014-02-26,2014-04'.\"
I then tried to change 2020-06-01-preview
to 2020-06-01
which returned an error of:
"No HTTP resource was found that matches the request URI 'https://management.azure.com/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>/providers/Microsoft.Resources/deployments/gbt-nprod-iac-eastus2-dealservice-cosmos/listConnectionStrings?api-version=2020-06-01'.\"
I know the issue is because a module doesn't contain the id and apiVersion properties so I then tried to use the outputs from the resource group.
I added to following line to cosmos-db.bicep:
output apiVersion string = cosmos.apiVersion
And also added the following to main.bicep:
var apiVersion = cosmos.outputs.apiVersion
// Key Vault Secret
resource kvsecret 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = if (deployDB || deployKV) {
...
properties: {
value: listConnectionStrings(cosmos.name, apiVersion).connectionStrings[0].connectionString
attributes: {
...
}
}
}
This resulted in a different error saying:
This expression is being used in an argument of the function "listConnectionStrings", which requires a value that can be calculated at the start of the deployment. You are referencing a variable which cannot be calculated at the start ("apiVersion" -> "cosmos"). Properties of cosmos which can be calculated at the start include "name".
My question is, is there another way to retrieve the Cosmos connection string for the key vault secret? If not, how can I correctly add Cosmos' API version to this listConnectionStrings()
function?