I am struggling with the Azure documentation and I am not finding any relevant examples that can help me defining an Azure runbook based on Bicep.
The official documentation doesn't provide much information about the possible parameters
https://learn.microsoft.com/en-us/azure/templates/microsoft.automation/automationaccounts/runbooks?pivots=deployment-language-bicep
Here is what I did
param runbookName string
param location string = resourceGroup().location
param automationAccount object
#allowed([
'Graph'
'GraphPowerShell'
'GraphPowerShellWorkflow'
'PowerShell'
'PowerShellWorkflow'
'Python2'
'Python3'
'Script'
])
param runbookType string = 'PowerShell'
param logProgress bool = true
param logVerbose bool = true
param logActivityTrace int = 0
resource runbookABC 'Microsoft.Automation/automationAccounts/runbooks#2019-06-01' = {
name: runbookName
location: location
parent: automationAccount
properties: {
description: 'Execute runbook ABC'
draft: {
draftContentLink: {
contentHash: {
algorithm: 'string' <<== 1) which values are allowed here?
value: loadTextContent('./scripts/abc.ps1') <<== 2) is this correct?
}
uri: 'string' <<== 3) what should I put here
version: 'v1.0'
}
inEdit: false
outputTypes: [
'varA' <<== 4) how the mapping is done here?
]
parameters: {}
}
logActivityTrace: logActivityTrace
logProgress: logProgress
logVerbose: logVerbose
runbookType: runbookType
}
}
As shown in the code above, I am unsure about the inputs:
contentHash > algorithm
contentHash > value
draftContentLink > uri
outputTypes
Any advices?
Thanks!
Related
How could I write environment URLs that should not be hardcoded in Bicep file ?
In this case, storageProfile uri and id.
Thx a lot !
My code in Bicep :
resource galleries_nicoGallery_name_nicoImageDef_-_-----_---- 'Microsoft.Compute/galleries/images/versions#2022-03-03' = {
parent: galleries_nicoGallery_name_nicoImageDef
name: '-.-----.----'
location: location
tags: {
baseosimg: 'ubuntu1804'
correlationId: '00000000-0000-0000-0000-000000000000'
source: 'azureVmImageBuilder'
}
properties: {
publishingProfile: {
targetRegions: [
{
name: 'France Central'
regionalReplicaCount: 1
storageAccountType: 'Standard_LRS'
}
{
name: 'West Europe'
regionalReplicaCount: 1
storageAccountType: 'Standard_LRS'
}
]
replicaCount: 1
excludeFromLatest: false
storageAccountType: 'Standard_LRS'
}
storageProfile: {
osDiskImage: {
hostCaching: 'ReadWrite'
source: {
uri: 'https://000000000000000000000000.blob.core.windows.net/vhds/00000000-0000-0000-0000-000000000000.vhd'
id: storageAccounts_000000000000000000000000_externalid
}
}
}
safetyProfile: {
allowDeletionOfReplicatedLocations: true
}
}
}
I tried to hardcode but this is not a good practice.
You can use Bicep Parameters and Variables. Every time you deploy a new Bicep you can provide new Parameter values directly from console. Otherwise, you can use parameter file.
You can also concat few values in a long string using parameters, variables or even function environment(). , which have predefined values, like "core.windows.net". More details in official documentation, some examples below.
Choose the best scenario for your situation.
param storageProfileSourceId string
var storageAccountName = 'somename'
var vhdId = 'someguid'
var storageProfileSourceUri = 'https://${storageAccountName}.blob.core.windows.net/vhds/${vhdId}.vhd'
source: {
uri: storageProfileSourceUri
id: storageProfileSourceId
}
I am trying to add KeyVault and access policy from Bicep, but it is adding unknown in the access policy. If I add the same from the portal it is correctly added.
param systemLabel string = 'developer-3'
param vaultName string = 'developer-3'
param location string = resourceGroup().location
param sku string = 'Standard'
param tenantId string = 'tenantId'
param objectId string = 'objectId'
#description('Tags that our resources need')
param tags object = {
displayName: 'keyvault-${toLower(systemLabel)}'
}
param enabledForDeployment bool = true
param enabledForTemplateDeployment bool = true
param enabledForDiskEncryption bool = true
param enableRbacAuthorization bool = false
param softDeleteRetentionInDays int = 90
resource keyvault 'Microsoft.KeyVault/vaults#2021-06-01-preview' = {
name: vaultName
location: location
tags: {
DisplayName: tags.displayName
}
properties: {
tenantId: tenantId
sku: {
family: 'A'
name: sku
}
accessPolicies: []
enabledForDeployment: enabledForDeployment
enabledForDiskEncryption: enabledForDiskEncryption
enabledForTemplateDeployment: enabledForTemplateDeployment
softDeleteRetentionInDays: softDeleteRetentionInDays
enableRbacAuthorization: enableRbacAuthorization
}
}
resource accessPolicies 'Microsoft.KeyVault/vaults/accessPolicies#2021-11-01-preview' = {
name: 'add'
parent: keyvault
properties: {
accessPolicies: [
{
tenantId: tenantId
objectId: objectId
permissions: {
secrets: [
'get'
'list'
]
}
}
]
}
}
The aim is to add both the keyvault and access policy from the Bicep.
#Thomas was right. I was using the wrong objectId though I copied the objectId from app registration service principle.
However, for anyone facing this issue. Add access policy to your keyvault from the portal (GUI) and then look for Export template in Automation section. The right object Id is there in the template.
I am trying to implement Azure SQL failover group using Bicep templates. The problem I have is, I am unable to figure out how to reference array of databases passed as parameter in failover group's database property. When assigning array values to database property it gives me an error of expecting string values whereas assigned was array, which of course isn't correct.
resource symbolicname 'Microsoft.Sql/servers/failoverGroups#2021-11-01-preview' = {
name: 'string'
tags: {
tagName1: 'tagValue1'
tagName2: 'tagValue2'
}
parent: resourceSymbolicName
properties: {
databases: [
'string'
]
partnerServers: [
{
id: 'string'
}
]
readWriteEndpoint: {
failoverPolicy: 'string'
failoverWithDataLossGracePeriodMinutes: int
}
}
}
Does anyone have any working example of Azure SQL failover group using Bicep templates or point me in the right direction on the solution?
Edit 1 - main.bicep :
This is the code that I am trying after adding Thomas's changes:
param databases array
param primarySqlServerName string
param drSqlServerName string
param failovergroupName string
module primarySql '***************' = {
Deploy primary SQL Server and database
}
module drSql '****************' = {
Deploy secondary SQL Server
}
resource sqlServerFailoverGroup 'Microsoft.Sql/servers/failoverGroups#2020-11-01-preview' = {
name: '${primarySqlServerName}/${failovergroupName}'
properties: {
databases: [for database in databases: resourceId('Microsoft.Sql/servers/databases', primarySqlServerName, database)]
readWriteEndpoint: {
failoverPolicy: 'Automatic'
failoverWithDataLossGracePeriodMinutes: 60
}
readOnlyEndpoint: {
failoverPolicy: 'Enabled'
}
partnerServers: [
{
id: resourceId('Microsoft.Sql/servers', drSqlServerName)
}
]
}
dependsOn: [
primarySql
drSql
]
}
Getting below error while deploying above:
Unable to process template language expressions for resource at line
'1' and column '1289'. 'Unable to evaluate template language function
'resourceId': all function arguments must be string literals. Please
see aka.ms/arm-template-expressions/#resourceid for usage details.
The databases property is an of string. The partnerServers property is an array of object.
Both expect the resource id of the databases and partner servers.
Here is a simple sample of deploying 2 sql servers and databases with a failover group
sql.bicep:
param location string = resourceGroup().location
param sqlServerName string
param sqlServerPrincipalType string
param sqlServerAadAdminName string
param sqlServerAadAdminId string
param databaseNames array
// Create the Server
resource sqlServer 'Microsoft.Sql/servers#2020-11-01-preview' = {
name: sqlServerName
location: location
tags: {}
properties: {
administrators: {
administratorType: 'ActiveDirectory'
principalType: sqlServerPrincipalType
login: sqlServerAadAdminName
sid: sqlServerAadAdminId
azureADOnlyAuthentication: true
}
}
}
// We create the database only in the primary region
resource database 'Microsoft.Sql/servers/databases#2020-08-01-preview' = [for databaseName in databaseNames: if (!empty(databaseNames)) {
name: '${sqlServer.name}/${empty(databaseNames) ? 'placeholder' : databaseName}'
location: location
sku: {
name: 'S0'
tier: 'Standard'
}
properties: {
sourceDatabaseId: sqlServer.id
}
}]
and the main.bicep file:
param failoverGroupName string
param primarySqlServerName string
param primaryLocation string
param secondarySqlServerName string
param secondaryLocation string
param sqlServerPrincipalType string
param sqlServerAadAdminName string
param sqlServerAadAdminId string
param databaseNames array
module primarySql 'sql.bicep' = {
name: 'primarySql'
params: {
location: primaryLocation
sqlServerName: primarySqlServerName
sqlServerPrincipalType: sqlServerPrincipalType
sqlServerAadAdminName: sqlServerAadAdminName
sqlServerAadAdminId: sqlServerAadAdminId
databaseNames: databaseNames
}
}
module secondarySql 'sql.bicep' = {
name: 'secondarySql'
params: {
location: secondaryLocation
sqlServerName: secondarySqlServerName
sqlServerPrincipalType: sqlServerPrincipalType
sqlServerAadAdminName: sqlServerAadAdminName
sqlServerAadAdminId: sqlServerAadAdminId
databaseNames: []
}
}
resource sqlServerFailoverGroup 'Microsoft.Sql/servers/failoverGroups#2020-11-01-preview' = {
name: '${primarySqlServerName}/${failoverGroupName}'
dependsOn: [ primarySql, secondarySql ]
properties: {
databases: [for dataBaseName in databaseNames: resourceId('Microsoft.Sql/servers/databases', primarySqlServerName, dataBaseName)]
readWriteEndpoint: {
failoverPolicy: 'Automatic'
failoverWithDataLossGracePeriodMinutes: 60
}
readOnlyEndpoint: {
failoverPolicy: 'Enabled'
}
partnerServers: [
{
id: resourceId(resourceGroup().name, 'Microsoft.Sql/servers', secondarySqlServerName)
}
]
}
}
I am creating two Azure App Services and 2 App Service Plans using For Loop but I need to pass the HostingPlanID from the AppService plan to each of the App Services, but I'm unable to access the output of the module.
I'm getting the following error
Cannot access properties of type "module[]". An "object" type is required.
within my App Service Plan Module, I am creating an output output hostingPlanId string = hostingPlan.id
But i can't reference this from my template (main.bicep)
hostingPlan: AppServicePlan.hostingPlan.id
Module:
param appPlanSkuCode string
param appPlanSkuTier string
param appPlanOS string
param appPlanSize string
param appPlanFamily string
param appPlanCapacity int
param hostingPlanName string
resource hostingPlan 'Microsoft.Web/serverfarms#2020-10-01' = {
name: hostingPlanName
location: resourceGroup().location
kind: appPlanOS
sku: {
name: appPlanSkuCode
tier: appPlanSkuTier
size: appPlanSize
family: appPlanFamily
capacity: appPlanCapacity
}
properties: {
perSiteScaling: false
maximumElasticWorkerCount: 1
isSpot: false
reserved: true
isXenon: false
hyperV: false
targetWorkerCount: 0
targetWorkerSizeId: 0
}
}
output hostingPlanId string = hostingPlan.id
Template:
module AppService '../../Modules/Azure.App.Service.template.bicep' = [for i in range(0, length(webAppSettings.webApps)): {
name: webAppSettings.webApps[i].appServiceType == 'functionApp' ? toLower('fnc-${webAppSettings.webApps[i].name}-${resourceGroupNameSuffix}') : toLower('web-${webAppSettings.webApps[i].name}-${resourceGroupNameSuffix}')
dependsOn: [
AppServicePlan
]
params: {
hostingPlan: AppServicePlan.hostingPlan.id
webAppSettings:webAppSettings
vnetSubnetID:webAppSettings.webApps[i].appPurpose == 'backend' ? '${backendvnetSubnetID}' : '${frontendvnetSubnetID}'
appServiceName:webAppSettings.webApps[i].appServiceType == 'functionApp' ? toLower('fnc-${webAppSettings.webApps[i].name}-${resourceGroupNameSuffix}') : toLower('web-${webAppSettings.webApps[i].name}-${resourceGroupNameSuffix}')
appServiceType: webAppSettings.webApps[i].appServiceType
LinuxFXVersion: webAppSettings.webApps[i].LinuxFX
}
}]
Any ideas where I am going wrong?
Thanks
If you have a hostingPlan.bicep file, you can reference it from the main.bicep file like that:
module hostingPlan 'hostingPlan.bicep' = {
name: 'hostingPlan'
params: {
...
}
}
You can then access the outputs of the module:
hostingPlan.outputs.hostingPlanId
Normally when creating Azure resources through Bicep modules I would have 2 files. One file designated to hold the parameterized resource and another file, the main file, which will consume that module.
As an example for creating an action group my resource file looks like:
action-group.bicep
param actionGroupName string
param groupShortName string
param emailReceivers array = []
// Alerting Action Group
resource action_group 'microsoft.insights/actionGroups#2019-06-01' = {
name: actionGroupName
location: 'global'
tags: {}
properties: {
groupShortName: groupShortName
enabled: true
emailReceivers: emailReceivers
}
}
This resource is then consumed as a module in the main file, main.bicep:
// Alerting Action Group
module actionGroup '../modules/alerts/alert-group.bicep' = {
name: 'action-group-dply'
params: {
actionGroupName: actionGroupName
groupShortName: actionGroupShortName
emailReceivers: [
{
name: '<Name of email receivers>'
emailAddress: alertEmailList
}
]
}
}
My pipeline references main.bicep and will deploy the listed resources in the file. My question is, is there a way to add a third file in the mix? One file to still hold the parameterized resource, one file to hold the associated resource modules, and the main.bicep file. The idea is to create various alerts throughout my existing resources but I don't want to add a ton of modules to main.bicep as it will quickly increase the complexity and amount of code in this file.
Is there a way that I can have this file of modules, and reference the entire file in main.bicep to still deployment from the original pipeline?
As an example:
alerts.bicep
param metricAlertsName string
param description string
param severity int
param enabled bool = true
param scopes array = []
param evaluationFrequency string
param windowSize string
param targetResourceRegion string = resourceGroup().location
param allOf array = []
param actionGroupName string
var actionGroupId = resourceId(resourceGroup().name, 'microsoft.insights/actionGroups', actionGroupName)
resource dealsMetricAlerts 'Microsoft.Insights/metricAlerts#2018-03-01' = {
name: metricAlertsName
location: 'global'
tags: {}
properties: {
description: description
severity: severity
enabled: enabled
scopes: scopes
evaluationFrequency: evaluationFrequency
windowSize: windowSize
targetResourceRegion: targetResourceRegion
criteria: {
'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'
allOf: allOf
}
actions: [
{
actionGroupId: actionGroupId
}
]
}
alert-modules.bicep
// Function/Web Apps 403 Error
module appServicePlan403Errors '../modules/alerts/alerts.bicep' = {
// Alert Logic
}
// Function/Web Apps 500 Error
module appServicePlan500Errors '../modules/alerts/alerts.bicep' = {
// Alert Logic
}
main.bicep
// Some reference to alert-modules.bicep so when the pipeline runs and looks for main.bicep, it will still deploy all the resources
You can call the module multiple times (in main.bicep or a module) using looping:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/loops
e.g.
param alertsCollection array = [
{
actionGroupName: 'group1'
groupShortName: 'g1'
emailReceivers: []
}
{
actionGroupName: 'group2'
groupShortName: 'g2'
emailReceivers: [
'foo#bar.com'
'bar#baz.com'
]
}
]
module alerts '../modules/alerts/alert-group.bicep' = [for alert in alertsCollection): {
name: '${alert.actionGroupName}'
params: {
actionGroupName: alert.actionGroupName
groupShortName: alert.groupShortName
emailReceivers: alert.emailReceivers
}
}]
You could simplify the params passing via:
module alerts '../modules/alerts/alert-group.bicep' = [for alert in alertsCollection): {
name: '${alert.actionGroupName}'
params: alert
}]
But you need to be really strict on the schema of the alertsCollection parameter...
That help?