Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 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
2 changes: 2 additions & 0 deletions Data/postgreSqlDatabases/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ A list of available Recipes for this resource type, including links to the Bicep
|Platform| IaC Language| Recipe Name | Stage |
|---|---|---|---|
| Kubernetes | Bicep | kubernetes-postgresql.bicep | Alpha |
| Kubernetes | Terraform | main.tf | Alpha |
| Azure | Bicep | azure-postgresql.bicep | Alpha |

## Recipe Input Properties

Expand Down
198 changes: 198 additions & 0 deletions Data/postgreSqlDatabases/recipes/azure/bicep/azure-postgresql.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
@description('Information about what resource is calling this Recipe. Generated by Radius.')
param context object

@description('Location for the PostgreSQL Flexible Server. Defaults to the resource group location.')
param postgresqlLocation string = resourceGroup().location

@description('PostgreSQL major version.')
param postgresqlVersion string = '16'

@description('Storage size in GB.')
param storageSizeGb int = 32

//////////////////////////////////////////
// Common Radius variables
//////////////////////////////////////////

var resourceName = context.resource.name
var applicationName = context.application != null ? context.application.name : ''
var environmentName = context.environment != null ? context.environment.name : ''

//////////////////////////////////////////
// Secrets connection
//////////////////////////////////////////

// The secretName property references a Radius.Security/secrets resource whose
// recipe provisions an Azure Key Vault and (optionally) a User-Assigned Identity.
// Radius resolves the connection and populates context.resource.connections with
// the secret resource's status, including computedValues and secrets.
//
// Radius wires connection data with full resource structure:
// context.resource.connections.<name>.properties.status.computedValues.<key>
// context.resource.connections.<name>.properties.status.secrets.<key>.Value

var secretName = context.resource.properties.secretName
var connections = context.resource.?connections ?? {}
#disable-next-line use-safe-access
var secretsConn = contains(connections, secretName) ? connections[secretName] : {}

var adminUsername = string(secretsConn.?properties.?status.?secrets.?USERNAME.?Value ?? '')
var adminPassword = string(secretsConn.?properties.?status.?secrets.?PASSWORD.?Value ?? '')

//////////////////////////////////////////
// PostgreSQL variables
//////////////////////////////////////////

var database = context.resource.properties.?database ?? 'postgres_db'
var sizeValue = context.resource.properties.?size ?? 'S'
var initSql = context.resource.properties.?initSql ?? ''
var hasInitSql = initSql != ''
var port = 5432

var uniqueSuffix = substring(uniqueString(context.resource.id), 0, 13)
var serverName = 'psql-${uniqueSuffix}'

var skuMap = {
S: {
name: 'Standard_B1ms'
tier: 'Burstable'
}
M: {
name: 'Standard_D2s_v3'
tier: 'GeneralPurpose'
}
L: {
name: 'Standard_E2ds_v4'
tier: 'MemoryOptimized'
}
}

var tags = {
'radapp.io-resource': resourceName
'radapp.io-application': applicationName
'radapp.io-environment': environmentName
}

//////////////////////////////////////////
// PostgreSQL Flexible Server
//////////////////////////////////////////

resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2024-08-01' = {
name: serverName
location: postgresqlLocation
tags: tags
sku: {
name: skuMap[sizeValue].name
tier: skuMap[sizeValue].tier
}
properties: {
version: postgresqlVersion
administratorLogin: adminUsername
#disable-next-line use-secure-value-for-secure-inputs
administratorLoginPassword: adminPassword
storage: {
storageSizeGB: storageSizeGb
}
backup: {
backupRetentionDays: 7
geoRedundantBackup: 'Disabled'
}
highAvailability: {
mode: 'Disabled'
}
}
}
Comment thread
willtsai marked this conversation as resolved.

resource firewallRule 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2024-08-01' = {
parent: postgresServer
name: 'AllowAllAzureServices'
properties: {
startIpAddress: '0.0.0.0'
endIpAddress: '0.0.0.0'
}
}

resource postgresDb 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2024-08-01' = {
parent: postgresServer
name: database
properties: {
charset: 'UTF8'
collation: 'en_US.utf8'
}
}

//////////////////////////////////////////
// Init SQL deployment script (optional)
//////////////////////////////////////////

// When `initSql` is provided, run it against the newly created database using
// `psql` inside an Azure CLI deployment script container. This mirrors the
// Kubernetes recipe's `/docker-entrypoint-initdb.d/` behavior, executing the
// SQL once after the database is provisioned. The script depends on the
// firewall rule that allows Azure services so the container can reach the
// flexible server.
resource initSqlScript 'Microsoft.Resources/deploymentScripts@2023-08-01' = if (hasInitSql) {
name: 'init-sql-${uniqueSuffix}'
location: postgresqlLocation
tags: tags
kind: 'AzureCLI'
properties: {
azCliVersion: '2.60.0'
timeout: 'PT10M'
retentionInterval: 'PT1H'
cleanupPreference: 'OnSuccess'
environmentVariables: [
{
name: 'PGHOST'
value: postgresServer.properties.fullyQualifiedDomainName
}
{
name: 'PGUSER'
value: adminUsername
}
{
name: 'PGPASSWORD'
secureValue: adminPassword
}
{
name: 'PGDATABASE'
value: postgresDb.name
}
{
name: 'PGPORT'
value: string(port)
}
{
name: 'PGSSLMODE'
value: 'require'
}
{
name: 'INIT_SQL'
secureValue: initSql
}
]
scriptContent: '''
set -euo pipefail
apk add --no-cache postgresql-client >/dev/null
printf '%s' "$INIT_SQL" | psql --quiet -v ON_ERROR_STOP=1 -f -
'''
}
dependsOn: [
firewallRule
]
}

//////////////////////////////////////////
// Output Radius result
//////////////////////////////////////////

output result object = {
resources: [
postgresServer.id
]
values: {
host: postgresServer.properties.fullyQualifiedDomainName
port: port
database: postgresDb.name
}
}