0

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?

Jeff
  • 265
  • 1
  • 4
agw2021
  • 266
  • 2
  • 22
  • I think you should use `cosmos.outputs.resource.id`, `cosmos.outputs.resource.apiVersion` if you define `output resource object = cosmos` and you module name is `cosmos`. – Thomas Sep 15 '21 at 05:32

0 Answers0