Skip to content

Commit

Permalink
Merge branch 'main' into release-please--branches--main
Browse files Browse the repository at this point in the history
  • Loading branch information
arealmaas authored Jul 29, 2024
2 parents 6f77a4c + 5895649 commit a7e1b94
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 109 deletions.
2 changes: 1 addition & 1 deletion .azure/bicepconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
},
"experimentalFeaturesEnabled": {
"compileTimeImports": true,
"userDefinedFunctions": false
"userDefinedFunctions": true
}
}
13 changes: 13 additions & 0 deletions .azure/functions/resourceName.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// This function generates a unique string based on the subscription ID and resource group ID
@export()
func uniqueStringBySubscriptionAndResourceGroup() string => uniqueString('${subscription().id}${resourceGroup().id}')

// This function generates a unique resource name by appending a unique string to the given name, ensuring the total length does not exceed the specified limit.
// It also ensures that the name is always postfixed with the full length of the unique string, which is 13 characters plus a dash.
// Example:
// uniqueResourceName(name: 'my-resource', limit: 50) => 'my-resource-1234567890123'
// Example:
// uniqueResourceName(name: 'my-resource', limit: 20) => 'my-res-1234567890123'
@export()
func uniqueResourceName(name string, limit int) string =>
'${take(name, limit - 13 - 1)}-${uniqueStringBySubscriptionAndResourceGroup()}'
7 changes: 6 additions & 1 deletion .azure/modules/appConfiguration/create.bicep
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { uniqueResourceName } from '../../functions/resourceName.bicep'

param namePrefix string
param location string

Expand All @@ -7,8 +9,11 @@ type Sku = {
}
param sku Sku

var appConfigNameMaxLength = 63
var appConfigName = uniqueResourceName('${namePrefix}-appConfiguration', appConfigNameMaxLength)

resource appConfig 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = {
name: '${namePrefix}-appConfiguration'
name: appConfigName
location: location
sku: sku
properties: {
Expand Down
230 changes: 135 additions & 95 deletions .azure/modules/functionApp/slackNotifier.bicep
Original file line number Diff line number Diff line change
@@ -1,138 +1,178 @@
import { uniqueStringBySubscriptionAndResourceGroup, uniqueResourceName } from '../../functions/resourceName.bicep'

param location string
param applicationInsightsName string
param namePrefix string
param keyVaultName string

@export()
type Sku = {
storageAccountName: 'Standard_LRS' | 'Standard_GRS' | 'Standard_RAGRS' | 'Standard_ZRS' | 'Premium_LRS' | 'Premium_ZRS'
applicationServicePlanName: 'F1' | 'D1' | 'B1' | 'B2' | 'B3' | 'S1' | 'S2' | 'S3' | 'P1' | 'P2' | 'P3' | 'P1V2' | 'P2V2' | 'P3V2' | 'I1' | 'I2' | 'I3' | 'Y1' | 'Y2' | 'Y3' | 'Y1v2' | 'Y2v2' | 'Y3v2' | 'Y1v2Isolated' | 'Y2v2Isolated' | 'Y3v2Isolated'
applicationServicePlanTier: 'Free' | 'Shared' | 'Basic' | 'Dynamic' | 'Standard' | 'Premium' | 'Isolated'
storageAccountName:
| 'Standard_LRS'
| 'Standard_GRS'
| 'Standard_RAGRS'
| 'Standard_ZRS'
| 'Premium_LRS'
| 'Premium_ZRS'
applicationServicePlanName:
| 'F1'
| 'D1'
| 'B1'
| 'B2'
| 'B3'
| 'S1'
| 'S2'
| 'S3'
| 'P1'
| 'P2'
| 'P3'
| 'P1V2'
| 'P2V2'
| 'P3V2'
| 'I1'
| 'I2'
| 'I3'
| 'Y1'
| 'Y2'
| 'Y3'
| 'Y1v2'
| 'Y2v2'
| 'Y3v2'
| 'Y1v2Isolated'
| 'Y2v2Isolated'
| 'Y3v2Isolated'
applicationServicePlanTier: 'Free' | 'Shared' | 'Basic' | 'Dynamic' | 'Standard' | 'Premium' | 'Isolated'
}
param sku Sku

// Storage account names only supports lower case and numbers
// todo: add name of function as param and turn this into a reusable module
var storageAccountName = '${replace(namePrefix, '-', '')}${substring('slacknotifier', 0, 10)}sa'
// We use uniqueStringBySubscriptionAndResourceGroup directly here to avoid having too short storage account name.
// This should be refactored to use one common storage account. Or one storage account for all app functions.
var storageAccountName = take(
replace('${'${namePrefix}-sn'}-${uniqueStringBySubscriptionAndResourceGroup()}', '-', ''),
24
)

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = {
name: storageAccountName
location: location
sku: {
name: sku.storageAccountName
}
kind: 'Storage'
properties: {
supportsHttpsTrafficOnly: true
defaultToOAuthAuthentication: true
minimumTlsVersion: 'TLS1_2'
}
name: storageAccountName
location: location
sku: {
name: sku.storageAccountName
}
kind: 'Storage'
properties: {
supportsHttpsTrafficOnly: true
defaultToOAuthAuthentication: true
minimumTlsVersion: 'TLS1_2'
}
}

resource applicationServicePlan 'Microsoft.Web/serverfarms@2023-12-01' = {
name: '${namePrefix}-slacknotifier-asp'
location: location
sku: {
name: sku.applicationServicePlanName
tier: sku.applicationServicePlanTier
}
properties: {}
name: '${namePrefix}-slacknotifier-asp'
location: location
sku: {
name: sku.applicationServicePlanName
tier: sku.applicationServicePlanTier
}
properties: {}
}

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = {
name: applicationInsightsName
name: applicationInsightsName
}

var functionAppName = '${namePrefix}-slacknotifier-fa'
var functionAppNameMaxLength = 40
var functionAppName = uniqueResourceName('${namePrefix}-slacknotifier-fa', functionAppNameMaxLength)
resource functionApp 'Microsoft.Web/sites@2023-12-01' = {
name: functionAppName
location: location
kind: 'functionapp'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: applicationServicePlan.id
publicNetworkAccess: 'Enabled'
siteConfig: {
// Setting/updating appSettings in separate module in order to not delete already deployed functions, see below
}
httpsOnly: true
name: functionAppName
location: location
kind: 'functionapp'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: applicationServicePlan.id
publicNetworkAccess: 'Enabled'
siteConfig: {
// Setting/updating appSettings in separate module in order to not delete already deployed functions, see below
}
httpsOnly: true
}
}

var appSettings = {
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
WEBSITE_CONTENTSHARE: toLower(functionAppName)
FUNCTIONS_EXTENSION_VERSION: '~4'
APPINSIGHTS_INSTRUMENTATIONKEY: applicationInsights.properties.InstrumentationKey
Slack__WebhookUrl: '@Microsoft.KeyVault(VaultName=${keyVaultName};SecretName=Slack--Webhook--Url)'
FUNCTIONS_WORKER_RUNTIME: 'dotnet-isolated'
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
WEBSITE_CONTENTSHARE: toLower(functionAppName)
FUNCTIONS_EXTENSION_VERSION: '~4'
APPINSIGHTS_INSTRUMENTATIONKEY: applicationInsights.properties.InstrumentationKey
Slack__WebhookUrl: '@Microsoft.KeyVault(VaultName=${keyVaultName};SecretName=Slack--Webhook--Url)'
FUNCTIONS_WORKER_RUNTIME: 'dotnet-isolated'
}

module updateAppSettings 'appSettings.bicep' = {
name: '${functionAppName}-appsettings'
params: {
webAppName: functionAppName
currentAppSettings: list(resourceId('Microsoft.Web/sites/config', functionAppName, 'appsettings'), '2023-01-01').properties
appSettings: appSettings
}
name: '${functionAppName}-appsettings'
params: {
webAppName: functionAppName
currentAppSettings: list(resourceId('Microsoft.Web/sites/config', functionAppName, 'appsettings'), '2023-01-01').properties
appSettings: appSettings
}
}

var defaultFunctionKey = listkeys('${functionApp.id}/host/default', '2023-01-01').functionKeys.default
var forwardAlertToSlackTriggerUrl = 'https://${functionApp.properties.defaultHostName}/api/forwardalerttoslack?code=${defaultFunctionKey}'
resource notifyDevTeam 'Microsoft.Insights/actionGroups@2023-01-01' = {
name: '${namePrefix}-notify-devteam-ag'
location: 'Global'
properties: {
enabled: true
groupShortName: 'DevNotify'
azureFunctionReceivers: [
{
name: functionApp.properties.defaultHostName
functionName: 'ForwardAlertToSlack'
functionAppResourceId: functionApp.id
httpTriggerUrl: forwardAlertToSlackTriggerUrl
useCommonAlertSchema: true
}
]
}
name: '${namePrefix}-notify-devteam-ag'
location: 'Global'
properties: {
enabled: true
groupShortName: 'DevNotify'
azureFunctionReceivers: [
{
name: functionApp.properties.defaultHostName
functionName: 'ForwardAlertToSlack'
functionAppResourceId: functionApp.id
httpTriggerUrl: forwardAlertToSlackTriggerUrl
useCommonAlertSchema: true
}
]
}
}

resource exceptionOccuredAlertRule 'Microsoft.Insights/scheduledQueryRules@2023-03-15-preview' = {
name: '${namePrefix}-exception-occured-sqr'
location: location
properties: {
enabled: true
severity: 1
evaluationFrequency: 'PT5M'
windowSize: 'PT5M'
scopes: [ applicationInsights.id ]
autoMitigate: false
targetResourceTypes: [
'microsoft.insights/components'
]
criteria: {
allOf: [
{
query: 'exceptions | summarize count = count() by environment = tostring(customDimensions.AspNetCoreEnvironment), problemId'
operator: 'GreaterThan'
threshold: 0
timeAggregation: 'Count'
failingPeriods: {
numberOfEvaluationPeriods: 1
minFailingPeriodsToAlert: 1
}
}
]
}
actions: {
actionGroups: [
notifyDevTeam.id
]
name: '${namePrefix}-exception-occured-sqr'
location: location
properties: {
enabled: true
severity: 1
evaluationFrequency: 'PT5M'
windowSize: 'PT5M'
scopes: [applicationInsights.id]
autoMitigate: false
targetResourceTypes: [
'microsoft.insights/components'
]
criteria: {
allOf: [
{
query: 'exceptions | summarize count = count() by environment = tostring(customDimensions.AspNetCoreEnvironment), problemId'
operator: 'GreaterThan'
threshold: 0
timeAggregation: 'Count'
failingPeriods: {
numberOfEvaluationPeriods: 1
minFailingPeriodsToAlert: 1
}
}
]
}
actions: {
actionGroups: [
notifyDevTeam.id
]
}
}
}

output functionAppPrincipalId string = functionApp.identity.principalId
6 changes: 5 additions & 1 deletion .azure/modules/postgreSql/create.bicep
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { uniqueResourceName } from '../../functions/resourceName.bicep'

param namePrefix string
param location string
param environmentKeyVaultName string
Expand All @@ -20,6 +22,8 @@ param administratorLoginPassword string

var administratorLogin = 'dialogportenPgAdmin'
var databaseName = 'dialogporten'
var postgresServerNameMaxLength = 63
var postgresServerName = uniqueResourceName('${namePrefix}-postgres', postgresServerNameMaxLength)

// Uncomment the following lines to add logical replication.
// see https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-logical#pre-requisites-for-logical-replication-and-logical-decoding
Expand Down Expand Up @@ -54,7 +58,7 @@ module privateDnsZone '../privateDnsZone/main.bicep' = {
}

resource postgres 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = {
name: '${namePrefix}-postgres'
name: postgresServerName
location: location
properties: {
version: '15'
Expand Down
18 changes: 14 additions & 4 deletions .azure/modules/redis/main.bicep
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
uniqueResourceName
} from '../../functions/resourceName.bicep'

param namePrefix string
param location string
param subnetId string
Expand All @@ -16,9 +20,12 @@ type Sku = {
}
param sku Sku

var redisNameMaxLength = 63
var redisName = uniqueResourceName('${namePrefix}-redis', redisNameMaxLength)

// https://learn.microsoft.com/en-us/azure/templates/microsoft.cache/redis?pivots=deployment-language-bicep
resource redis 'Microsoft.Cache/Redis@2023-08-01' = {
name: '${namePrefix}-redis'
name: redisName
location: location
identity: {
type: 'SystemAssigned'
Expand All @@ -35,13 +42,16 @@ resource redis 'Microsoft.Cache/Redis@2023-08-01' = {
}
}

// private endpoint name max characters is 80
var redisPrivateEndpointName = uniqueResourceName('${namePrefix}-redis-pe', 80)

resource redisPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = {
name: '${namePrefix}-redis-pe'
name: redisPrivateEndpointName
location: location
properties: {
privateLinkServiceConnections: [
{
name: '${namePrefix}-redis-pe'
name: redisPrivateEndpointName
properties: {
privateLinkServiceId: redis.id
groupIds: [
Expand All @@ -50,7 +60,7 @@ resource redisPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' =
}
}
]
customNetworkInterfaceName: '${namePrefix}-redis-pe-nic'
customNetworkInterfaceName: uniqueResourceName('${namePrefix}-redis-pe-nic', 80)
subnet: {
id: subnetId
}
Expand Down
Loading

0 comments on commit a7e1b94

Please sign in to comment.