2025-04-22 11:46:24 +02:00
{
"$schema" : "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#" ,
"contentVersion" : "1.0.0.0" ,
"metadata" : {
"_generator" : {
"name" : "bicep" ,
2025-06-10 10:56:50 +02:00
"version" : "0.36.1.42791" ,
2025-07-21 21:02:53 +02:00
"templateHash" : "4391955326311642567"
2025-04-22 11:46:24 +02:00
}
} ,
"parameters" : {
"stackName" : {
"type" : "string" ,
"metadata" : {
"description" : "Stack name"
}
} ,
"certificateType" : {
"type" : "string" ,
"defaultValue" : "selfsigned" ,
"allowedValues" : [
"selfsigned" ,
"owncert" ,
"letsencrypt"
] ,
"metadata" : {
"description" : "[selfsigned] Not recommended for production use. If you don't have a FQDN, (DomainName parameter) you can use this option to generate a self-signed certificate.\n[owncert] Valid for productions environments. If you have a FQDN, (DomainName parameter)\nand an Elastic IP, you can use this option to use your own certificate.\n[letsencrypt] Valid for production environments. If you have a FQDN, (DomainName parameter)\nand an Elastic IP, you can use this option to generate a Let's Encrypt certificate.\n"
}
} ,
2025-05-23 13:53:24 +02:00
"publicIpAddressObject" : {
"type" : "object" ,
2025-04-22 11:46:24 +02:00
"metadata" : {
"description" : "Previously created Public IP address for the OpenVidu Deployment. Blank will generate a public IP"
}
} ,
"domainName" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "Domain name for the OpenVidu Deployment. Blank will generate default domain"
}
} ,
"ownPublicCertificate" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "If certificate type is 'owncert', this parameter will be used to specify the public certificate"
}
} ,
"ownPrivateCertificate" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "If certificate type is 'owncert', this parameter will be used to specify the private certificate"
}
} ,
"letsEncryptEmail" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "If certificate type is 'letsencrypt', this email will be used for Let's Encrypt notifications"
}
} ,
"turnDomainName" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "(Optional) Domain name for the TURN server with TLS. Only needed if your users are behind restrictive firewalls"
}
} ,
"turnOwnPublicCertificate" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "(Optional) This setting is applicable if the certificate type is set to 'owncert' and the TurnDomainName is specified."
}
} ,
"turnOwnPrivateCertificate" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "(Optional) This setting is applicable if the certificate type is set to 'owncert' and the TurnDomainName is specified."
}
} ,
"openviduLicense" : {
"type" : "securestring" ,
"metadata" : {
"description" : "Visit https://openvidu.io/account"
}
} ,
"rtcEngine" : {
"type" : "string" ,
"defaultValue" : "pion" ,
"allowedValues" : [
"pion" ,
"mediasoup"
] ,
"metadata" : {
"description" : "RTCEngine media engine to use"
}
} ,
"masterNodeInstanceType" : {
"type" : "string" ,
"defaultValue" : "Standard_B2s" ,
"allowedValues" : [
"Standard_B1s" ,
"Standard_B1ms" ,
"Standard_B2s" ,
"Standard_B2ms" ,
"Standard_B4ms" ,
"Standard_B8ms" ,
"Standard_D2_v3" ,
"Standard_D4_v3" ,
"Standard_D8_v3" ,
"Standard_D16_v3" ,
"Standard_D32_v3" ,
"Standard_D48_v3" ,
"Standard_D64_v3" ,
"Standard_D2_v4" ,
"Standard_D4_v4" ,
"Standard_D8_v4" ,
"Standard_D16_v4" ,
"Standard_D32_v4" ,
"Standard_D48_v4" ,
"Standard_D64_v4" ,
"Standard_D96_v4" ,
"Standard_D2_v5" ,
"Standard_D4_v5" ,
"Standard_D8_v5" ,
"Standard_D16_v5" ,
"Standard_D32_v5" ,
"Standard_D48_v5" ,
"Standard_D64_v5" ,
"Standard_D96_v5" ,
"Standard_F2" ,
"Standard_F4" ,
"Standard_F8" ,
"Standard_F16" ,
"Standard_F32" ,
"Standard_F64" ,
"Standard_F72" ,
"Standard_F2s_v2" ,
"Standard_F4s_v2" ,
"Standard_F8s_v2" ,
"Standard_F16s_v2" ,
"Standard_F32s_v2" ,
"Standard_F64s_v2" ,
"Standard_F72s_v2" ,
"Standard_E2_v3" ,
"Standard_E4_v3" ,
"Standard_E8_v3" ,
"Standard_E16_v3" ,
"Standard_E32_v3" ,
"Standard_E48_v3" ,
"Standard_E64_v3" ,
"Standard_E96_v3" ,
"Standard_E2_v4" ,
"Standard_E4_v4" ,
"Standard_E8_v4" ,
"Standard_E16_v4" ,
"Standard_E32_v4" ,
"Standard_E48_v4" ,
"Standard_E64_v4" ,
"Standard_E2_v5" ,
"Standard_E4_v5" ,
"Standard_E8_v5" ,
"Standard_E16_v5" ,
"Standard_E32_v5" ,
"Standard_E48_v5" ,
"Standard_E64_v5" ,
"Standard_E96_v5" ,
"Standard_M64" ,
"Standard_M128" ,
"Standard_M208ms_v2" ,
"Standard_M416ms_v2" ,
"Standard_L4s_v2" ,
"Standard_L8s_v2" ,
"Standard_L16s_v2" ,
"Standard_L32s_v2" ,
"Standard_L64s_v2" ,
"Standard_L80s_v2" ,
"Standard_NC6" ,
"Standard_NC12" ,
"Standard_NC24" ,
"Standard_NC24r" ,
"Standard_ND6s" ,
"Standard_ND12s" ,
"Standard_ND24s" ,
"Standard_ND24rs" ,
"Standard_NV6" ,
"Standard_NV12" ,
"Standard_NV24" ,
"Standard_H8" ,
"Standard_H16" ,
"Standard_H16r" ,
"Standard_H16mr" ,
"Standard_HB120rs_v2" ,
"Standard_HC44rs" ,
"Standard_DC2s" ,
"Standard_DC4s" ,
"Standard_DC2s_v2" ,
"Standard_DC4s_v2" ,
"Standard_DC8s_v2" ,
"Standard_DC16s_v2" ,
"Standard_DC32s_v2" ,
"Standard_A1_v2" ,
"Standard_A2_v2" ,
"Standard_A4_v2" ,
"Standard_A8_v2" ,
"Standard_A2m_v2" ,
"Standard_A4m_v2" ,
"Standard_A8m_v2"
] ,
"metadata" : {
"description" : "Specifies the EC2 instance type for your OpenVidu Master Node"
}
} ,
"mediaNodeInstanceType" : {
"type" : "string" ,
"defaultValue" : "Standard_B2s" ,
"allowedValues" : [
"Standard_B1s" ,
"Standard_B1ms" ,
"Standard_B2s" ,
"Standard_B2ms" ,
"Standard_B4ms" ,
"Standard_B8ms" ,
"Standard_D2_v3" ,
"Standard_D4_v3" ,
"Standard_D8_v3" ,
"Standard_D16_v3" ,
"Standard_D32_v3" ,
"Standard_D48_v3" ,
"Standard_D64_v3" ,
"Standard_D2_v4" ,
"Standard_D4_v4" ,
"Standard_D8_v4" ,
"Standard_D16_v4" ,
"Standard_D32_v4" ,
"Standard_D48_v4" ,
"Standard_D64_v4" ,
"Standard_D96_v4" ,
"Standard_D2_v5" ,
"Standard_D4_v5" ,
"Standard_D8_v5" ,
"Standard_D16_v5" ,
"Standard_D32_v5" ,
"Standard_D48_v5" ,
"Standard_D64_v5" ,
"Standard_D96_v5" ,
"Standard_F2" ,
"Standard_F4" ,
"Standard_F8" ,
"Standard_F16" ,
"Standard_F32" ,
"Standard_F64" ,
"Standard_F72" ,
"Standard_F2s_v2" ,
"Standard_F4s_v2" ,
"Standard_F8s_v2" ,
"Standard_F16s_v2" ,
"Standard_F32s_v2" ,
"Standard_F64s_v2" ,
"Standard_F72s_v2" ,
"Standard_E2_v3" ,
"Standard_E4_v3" ,
"Standard_E8_v3" ,
"Standard_E16_v3" ,
"Standard_E32_v3" ,
"Standard_E48_v3" ,
"Standard_E64_v3" ,
"Standard_E96_v3" ,
"Standard_E2_v4" ,
"Standard_E4_v4" ,
"Standard_E8_v4" ,
"Standard_E16_v4" ,
"Standard_E32_v4" ,
"Standard_E48_v4" ,
"Standard_E64_v4" ,
"Standard_E2_v5" ,
"Standard_E4_v5" ,
"Standard_E8_v5" ,
"Standard_E16_v5" ,
"Standard_E32_v5" ,
"Standard_E48_v5" ,
"Standard_E64_v5" ,
"Standard_E96_v5" ,
"Standard_M64" ,
"Standard_M128" ,
"Standard_M208ms_v2" ,
"Standard_M416ms_v2" ,
"Standard_L4s_v2" ,
"Standard_L8s_v2" ,
"Standard_L16s_v2" ,
"Standard_L32s_v2" ,
"Standard_L64s_v2" ,
"Standard_L80s_v2" ,
"Standard_NC6" ,
"Standard_NC12" ,
"Standard_NC24" ,
"Standard_NC24r" ,
"Standard_ND6s" ,
"Standard_ND12s" ,
"Standard_ND24s" ,
"Standard_ND24rs" ,
"Standard_NV6" ,
"Standard_NV12" ,
"Standard_NV24" ,
"Standard_H8" ,
"Standard_H16" ,
"Standard_H16r" ,
"Standard_H16mr" ,
"Standard_HB120rs_v2" ,
"Standard_HC44rs" ,
"Standard_DC2s" ,
"Standard_DC4s" ,
"Standard_DC2s_v2" ,
"Standard_DC4s_v2" ,
"Standard_DC8s_v2" ,
"Standard_DC16s_v2" ,
"Standard_DC32s_v2" ,
"Standard_A1_v2" ,
"Standard_A2_v2" ,
"Standard_A4_v2" ,
"Standard_A8_v2" ,
"Standard_A2m_v2" ,
"Standard_A4m_v2" ,
"Standard_A8m_v2"
] ,
"metadata" : {
"description" : "Specifies the EC2 instance type for your OpenVidu Media Nodes"
}
} ,
"adminUsername" : {
"type" : "string" ,
"metadata" : {
"description" : "Username for the Virtual Machine."
}
} ,
"adminSshKey" : {
2025-05-23 13:53:24 +02:00
"type" : "secureObject" ,
2025-04-22 11:46:24 +02:00
"metadata" : {
"description" : "SSH Key or password for the Virtual Machine"
}
} ,
"initialNumberOfMediaNodes" : {
"type" : "int" ,
"defaultValue" : 1 ,
"metadata" : {
"description" : "Number of initial media nodes to deploy"
}
} ,
"minNumberOfMediaNodes" : {
"type" : "int" ,
"defaultValue" : 1 ,
"metadata" : {
"description" : "Minimum number of media nodes to deploy"
}
} ,
"maxNumberOfMediaNodes" : {
"type" : "int" ,
"defaultValue" : 5 ,
"metadata" : {
"description" : "Maximum number of media nodes to deploy"
}
} ,
"scaleTargetCPU" : {
"type" : "int" ,
"defaultValue" : 50 ,
"metadata" : {
"description" : "Target CPU percentage to scale up or down"
}
} ,
2025-06-18 16:26:50 +02:00
"additionalInstallFlags" : {
"type" : "string" ,
"defaultValue" : ""
} ,
2025-04-22 11:46:24 +02:00
"datetime" : {
"type" : "string" ,
"defaultValue" : "[utcNow('u')]"
} ,
"automationAccountName" : {
"type" : "string" ,
2025-05-27 11:18:05 +02:00
"defaultValue" : "" ,
2025-04-22 11:46:24 +02:00
"metadata" : {
"description" : "Automation Account Name to create a runbook inside it for scale in"
}
2025-04-23 13:26:33 +02:00
} ,
2025-05-13 11:01:22 +02:00
"storageAccountName" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
"description" : "Name of the existing storage account. It is essential that this parameter is filled just when you want to save recordings and still using the same container after an update. If not specified, a new storage account will be generated."
}
} ,
2025-04-23 13:26:33 +02:00
"containerName" : {
"type" : "string" ,
"defaultValue" : "" ,
"metadata" : {
2025-05-20 18:46:31 +02:00
"description" : "Name of the bucket where OpenVidu will store the recordings if a new Storage account is being creating. If not specified, a default bucket will be created. If you want to use an existing storage account, fill this parameter with the name of the container where the recordings are stored."
2025-04-23 13:26:33 +02:00
}
2025-04-22 11:46:24 +02:00
}
} ,
"variables" : {
2025-05-23 13:53:24 +02:00
"isEmptyIp" : "[equals(parameters('publicIpAddressObject').newOrExistingOrNone, 'none')]" ,
2025-04-22 11:46:24 +02:00
"isEmptyDomain" : "[equals(parameters('domainName'), '')]" ,
"masterNodeVMSettings" : {
2025-05-23 13:53:24 +02:00
"vmName" : "[format('{0}-VM-MasterNode', parameters('stackName'))]" ,
2025-04-22 11:46:24 +02:00
"osDiskType" : "StandardSSD_LRS" ,
"ubuntuOSVersion" : {
"publisher" : "Canonical" ,
"offer" : "0001-com-ubuntu-server-jammy" ,
"sku" : "22_04-lts-gen2" ,
"version" : "latest"
} ,
"linuxConfiguration" : {
"disablePasswordAuthentication" : true ,
"ssh" : {
"publicKeys" : [
{
"path" : "[format('/home/{0}/.ssh/authorized_keys', parameters('adminUsername'))]" ,
2025-05-23 13:53:24 +02:00
"keyData" : "[parameters('adminSshKey').sshPublicKey]"
2025-04-22 11:46:24 +02:00
}
]
}
}
} ,
"mediaNodeVMSettings" : {
"vmName" : "[format('{0}-VM-MediaNode', parameters('stackName'))]" ,
"osDiskType" : "StandardSSD_LRS" ,
"ubuntuOSVersion" : {
"publisher" : "Canonical" ,
"offer" : "0001-com-ubuntu-server-jammy" ,
"sku" : "22_04-lts-gen2" ,
"version" : "latest"
} ,
"linuxConfiguration" : {
"disablePasswordAuthentication" : true ,
"ssh" : {
"publicKeys" : [
{
"path" : "[format('/home/{0}/.ssh/authorized_keys', parameters('adminUsername'))]" ,
2025-05-23 13:53:24 +02:00
"keyData" : "[parameters('adminSshKey').sshPublicKey]"
2025-04-22 11:46:24 +02:00
}
]
}
}
} ,
"networkSettings" : {
"vNetAddressPrefix" : "10.0.0.0/16" ,
"subnetAddressPrefixMaster1" : "10.0.1.0/24" ,
"subnetAddressPrefixMedia" : "10.0.0.0/24" ,
"vNetName" : "[format('{0}-virtualNetwork', parameters('stackName'))]"
} ,
"keyVaultName" : "[format('{0}-keyvault', parameters('stackName'))]" ,
"location" : "[resourceGroup().location]" ,
"tenantId" : "[subscription().tenantId]" ,
"deploymentUser" : "[deployer().objectId]" ,
2025-07-21 21:02:53 +02:00
"installScriptTemplateMaster" : "#!/bin/bash -x\nOPENVIDU_VERSION=main\nDOMAIN=\n\n# Assume azure cli is installed\n\napt-get update && apt-get install -y \\\n curl \\\n unzip \\\n jq \\\n wget\n\n# Configure Domain\nif [[ \"${domainName}\" == '' ]]; then\n DOMAIN=${fqdn}\nelse\n DOMAIN=${domainName}\nfi\n\n# Wait for the keyvault availability\nMAX_WAIT=100\nWAIT_INTERVAL=1\nELAPSED_TIME=0\nwhile true; do\n # Check keyvault availability\n set +e\n az keyvault secret list --vault-name ${keyVaultName}\n\n # If it is available, exit the loop\n if [ $? -eq 0 ]; then\n break\n fi\n\n # If not, wait and check again incrementing the time\n ELAPSED_TIME=$((ELAPSED_TIME + WAIT_INTERVAL))\n\n # If exceeded the maximum time, exit with error\n if [ $ELAPSED_TIME -ge $MAX_WAIT ]; then\n exit 1\n fi\n\n # Wait for the next iteration\n sleep $WAIT_INTERVAL\ndone\nset -e\n\n# Get own private IP\nPRIVATE_IP=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text\")\n\n\n# Store usernames and generate random passwords\nDOMAIN=\"$(/usr/local/bin/store_secret.sh save DOMAIN-NAME \"$DOMAIN\")\"\nOPENVIDU_PRO_LICENSE=\"$(/usr/local/bin/store_secret.sh save OPENVIDU-PRO-LICENSE \"${openviduLicense}\")\"\nOPENVIDU_RTC_ENGINE=\"$(/usr/local/bin/store_secret.sh save OPENVIDU-RTC-ENGINE \"${rtcEngine}\")\"\nREDIS_PASSWORD=\"$(/usr/local/bin/store_secret.sh generate REDIS-PASSWORD)\"\nMONGO_ADMIN_USERNAME=\"$(/usr/local/bin/store_secret.sh save MONGO-ADMIN-USERNAME \"mongoadmin\")\"\nMONGO_ADMIN_PASSWORD=\"$(/usr/local/bin/store_secret.sh generate MONGO-ADMIN-PASSWORD)\"\nMONGO_REPLICA_SET_KEY=\"$(/usr/local/bin/store_secret.sh generate MONGO-REPLICA-SET-KEY)\"\nMINIO_ACCESS_KEY=\"$(/usr/local/bin/store_secret.sh save MINIO-ACCESS-KEY \"minioadmin\")\"\nMINIO_SECRET_KEY=\"$(/usr/local/bin/store_secret.sh generate MINIO-SECRET-KEY)\"\nDASHBOARD_ADMIN_USERNAME=\"$(/usr/local/bin/store_secret.sh save DASHBOARD-ADMIN-USERNAME \"dashboardadmin\")\"\nDASHBOARD_ADMIN_PASSWORD=\"$(/usr/local/bin/store_secret.sh generate DASHBOARD-ADMIN-PASSWORD)\"\nGRAFANA_ADMIN_USERNAME=\"$(/usr/local/bin/store_secret.sh save GRAFANA-ADMIN-USERNAME \"grafanaadmin\")\"\nGRAFANA_ADMIN_PASSWORD=\"$(/usr/local/bin/store_secret.sh generate GRAFANA-ADMIN-PASSWORD)\"\nMEET_ADMIN_USER=\"$(/usr/local/bin/store_secret.sh save MEET-ADMIN-USER \"meetadmin\")\"\nMEET_ADMIN_SECRET=\"$(/usr/local/bin/store_secret.sh generate MEET-ADMIN-SECRET)\"\nMEET_API_KEY=\"$(/usr/local/bin/store_secret.sh generate MEET-API-KEY)\"\nLIVEKIT_API_KEY=\"$(/usr/local/bin/store_secret.sh generate LIVEKIT-API-KEY \"API\" 12)\"\nLIVEKIT_API_SECRET=\"$(/usr/local/bin/store_secret.sh generate LIVEKIT-API-SECRET)\"\nOPENVIDU_VERSION=\"$(/usr/local/bin/store_secret.sh save OPENVIDU-VERSION \"${OPENVIDU_VERSION}\")\"\nENABLED_MODULES=\"$(/usr/local/bin/store_secret.sh save ENABLED-MODULES \"observability,openviduMeet,v2compatibility\")\"\nALL_SECRETS_GENERATED=\"$(/usr/local/bin/store_secret.sh save ALL-SECRETS-GENERATED \"true\")\"\n\n# Base command\nINSTALL_COMMAND=\"sh <(curl -fsSL http://get.openvidu.io/pro/elastic/$OPENVIDU_VERSION/install_ov_master_node.sh)\"\n\n# Common arguments\nCOMMON_ARGS=(\n \"--no-tty\"\n \"--install\"\n \"--environment=azure\"\n \"--deployment-type=elastic\"\n \"--node-role='master-node'\"\n \"--openvidu-pro-license=$OPENVIDU_PRO_LICENSE\"\n \"--private-ip=$PRIVATE_IP\"\n \"--domain-name=$DOMAIN\"\n \"--enabled-modules='$ENABLED_MODULES'\"\n \"--rtc-engine=$OPENVIDU_RTC_ENGINE\"\n \"--redis-password=$REDIS_PASSWORD\"\n \"--mongo-admin-user=$MONGO_ADMIN_USERNAME\"\n \"--mongo-admin-password=$MONGO_ADMIN_PASSWORD\"\n \"--mongo-replica-set-key=$MONGO_REPLICA_SET_KEY\"\n \"--minio-access-key=$MINIO_ACCESS_KEY\"\n \"--minio-secret-key=$MINIO_SECRET_KEY\"\n \"--dashboard-admin-user=$DASHBOARD_ADMIN_USERNAME\"\n \"--dashboard-admin-password=$DASHBOARD_ADMIN_PASSWORD\"\n \"--grafana-admin-user=$GRAFANA_ADMIN_USERNAME\"\n \" - - g r
2025-04-22 11:46:24 +02:00
"after_installScriptTemplateMaster" : "#!/bin/bash\nset -e\n\naz login --identity --allow-no-subscriptions > /dev/null\n\n# Configure Domain\nif [[ \"${domainName}\" == '' ]]; then\n DOMAIN=${fqdn}\nelse\n DOMAIN=${domainName}\nfi\n\n# Generate URLs\nDASHBOARD_URL=\"https://${DOMAIN}/dashboard/\"\nGRAFANA_URL=\"https://${DOMAIN}/grafana/\"\nMINIO_URL=\"https://${DOMAIN}/minio-console/\"\n\n# Update shared secret\naz keyvault secret set --vault-name ${keyVaultName} --name DOMAIN-NAME --value $DOMAIN\naz keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-URL --value $DASHBOARD_URL\naz keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-URL --value $GRAFANA_URL\naz keyvault secret set --vault-name ${keyVaultName} --name MINIO-URL --value $MINIO_URL\n\naz keyvault secret show --vault-name ${keyVaultName} --name MINIO-URL\n\nif [[ $? -ne 0 ]]; then\n echo \"Error updating keyvault\"\nfi\n" ,
2025-07-21 21:02:53 +02:00
"update_config_from_secretScriptTemplateMaster" : "#!/bin/bash\nset -e\n\naz login --identity --allow-no-subscriptions > /dev/null\n\n# Installation directory\nINSTALL_DIR=\"/opt/openvidu\"\nCLUSTER_CONFIG_DIR=\"${INSTALL_DIR}/config/cluster\"\nMASTER_NODE_CONFIG_DIR=\"${INSTALL_DIR}/config/node\"\n\n# Replace DOMAIN_NAME\nexport DOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)\nif [[ -n \"$DOMAIN\" ]]; then\n sed -i \"s/DOMAIN_NAME=.*/DOMAIN_NAME=$DOMAIN/\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nelse\n exit 1\nfi\n\n# Replace LIVEKIT_TURN_DOMAIN_NAME\nexport LIVEKIT_TURN_DOMAIN_NAME=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-TURN-DOMAIN-NAME --query value -o tsv)\nif [[ -n \"$LIVEKIT_TURN_DOMAIN_NAME\" ]]; then\n sed -i \"s/LIVEKIT_TURN_DOMAIN_NAME=.*/LIVEKIT_TURN_DOMAIN_NAME=$LIVEKIT_TURN_DOMAIN_NAME/\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nfi\n\nif [[ ${certificateType} == \"letsencrypt\" ]]; then\n export LETSENCRYPT_EMAIL=$(az keyvault secret show --vault-name ${keyVaultName} --name LETSENCRYPT-EMAIL --query value -o tsv)\n sed -i \"s/LETSENCRYPT_EMAIL=.*/LETSENCRYPT_EMAIL=$LETSENCRYPT_EMAIL/\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nfi\n\n# Get the rest of the values\nexport REDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)\nexport OPENVIDU_RTC_ENGINE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-RTC-ENGINE --query value -o tsv)\nexport OPENVIDU_PRO_LICENSE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --query value -o tsv)\nexport MONGO_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-USERNAME --query value -o tsv)\nexport MONGO_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-PASSWORD --query value -o tsv)\nexport MONGO_REPLICA_SET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-REPLICA-SET-KEY --query value -o tsv)\nexport DASHBOARD_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-USERNAME --query value -o tsv)\nexport DASHBOARD_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-PASSWORD --query value -o tsv)\nexport MINIO_ACCESS_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-ACCESS-KEY --query value -o tsv)\nexport MINIO_SECRET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-SECRET-KEY --query value -o tsv)\nexport GRAFANA_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-USERNAME --query value -o tsv)\nexport GRAFANA_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-PASSWORD --query value -o tsv)\nexport LIVEKIT_API_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-KEY --query value -o tsv)\nexport LIVEKIT_API_SECRET=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-SECRET --query value -o tsv)\nexport MEET_ADMIN_USER=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-ADMIN-USER --query value -o tsv)\nexport MEET_ADMIN_SECRET=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-ADMIN-SECRET --query value -o tsv)\nexport MEET_API_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-API-KEY --query value -o tsv)\nexport ENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)\n\n# Replace rest of the values\nsed -i \"s/REDIS_PASSWORD=.*/REDIS_PASSWORD=$REDIS_PASSWORD/\" \"${MASTER_NODE_CONFIG_DIR}/master_node.env\"\nsed -i \"s/OPENVIDU_RTC_ENGINE=.*/OPENVIDU_RTC_ENGINE=$OPENVIDU_RTC_ENGINE/\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nsed -i \"s/OPENVIDU_PRO_LICENSE=.*/OPENVIDU_PRO_LICENSE=$OPENVIDU_PRO_LICENSE/\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nsed -i \" s / M O N G O _ A D M I N _ U S E R N A M E = . * / M O N G O _ A D M I N _ U S E R N A M E = $ M O N G O _ A D M I
"update_secret_from_configScriptTemplateMaster" : "#!/bin/bash\nset -e\n\naz login --identity --allow-no-subscriptions > /dev/null\n\n# Installation directory\nINSTALL_DIR=\"/opt/openvidu\"\nCLUSTER_CONFIG_DIR=\"${INSTALL_DIR}/config/cluster\"\nMASTER_NODE_CONFIG_DIR=\"${INSTALL_DIR}/config/node\"\n\nif [[ ${certificateType} == \"letsencrypt\" ]]; then\n LETSENCRYPT_EMAIL=\"$(/usr/local/bin/get_value_from_config.sh LETSENCRYPT_EMAIL \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\n az keyvault secret set --vault-name ${keyVaultName} --name \"LETSENCRYPT-EMAIL\" --value $LETSENCRYPT_EMAIL\nfi\n\n# Get current values of the config\nREDIS_PASSWORD=\"$(/usr/local/bin/get_value_from_config.sh REDIS_PASSWORD \"${MASTER_NODE_CONFIG_DIR}/master_node.env\")\"\nDOMAIN_NAME=\"$(/usr/local/bin/get_value_from_config.sh DOMAIN_NAME \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nLIVEKIT_TURN_DOMAIN_NAME=\"$(/usr/local/bin/get_value_from_config.sh LIVEKIT_TURN_DOMAIN_NAME \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nOPENVIDU_RTC_ENGINE=\"$(/usr/local/bin/get_value_from_config.sh OPENVIDU_RTC_ENGINE \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nOPENVIDU_PRO_LICENSE=\"$(/usr/local/bin/get_value_from_config.sh OPENVIDU_PRO_LICENSE \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nMONGO_ADMIN_USERNAME=\"$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_USERNAME \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nMONGO_ADMIN_PASSWORD=\"$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_PASSWORD \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nMONGO_REPLICA_SET_KEY=\"$(/usr/local/bin/get_value_from_config.sh MONGO_REPLICA_SET_KEY \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nMINIO_ACCESS_KEY=\"$(/usr/local/bin/get_value_from_config.sh MINIO_ACCESS_KEY \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nMINIO_SECRET_KEY=\"$(/usr/local/bin/get_value_from_config.sh MINIO_SECRET_KEY \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nDASHBOARD_ADMIN_USERNAME=\"$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_USERNAME \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nDASHBOARD_ADMIN_PASSWORD=\"$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_PASSWORD \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nGRAFANA_ADMIN_USERNAME=\"$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_USERNAME \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nGRAFANA_ADMIN_PASSWORD=\"$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_PASSWORD \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nLIVEKIT_API_KEY=\"$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_KEY \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nLIVEKIT_API_SECRET=\"$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_SECRET \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\"\nMEET_ADMIN_USER=\"$(/usr/local/bin/get_value_from_config.sh MEET_ADMIN_USER \"${CLUSTER_CONFIG_DIR}/master_node/meet.env\")\"\nMEET_ADMIN_SECRET=\"$(/usr/local/bin/get_value_from_config.sh MEET_ADMIN_SECRET \"${CLUSTER_CONFIG_DIR}/master_node/meet.env\")\"\nMEET_API_KEY=\"$(/usr/local/bin/get_value_from_config.sh MEET_API_KEY \"${CLUSTER_CONFIG_DIR}/master_node/meet.env\")\"\nENABLED_MODULES=\"$(/usr/local/bin/get_value_from_config.sh ENABLED_MODULES \"${CLUSTER_CONFIG_DIR}/openvidu.env\")\" \ n \ n # U p d a t e s h a r e d s e c r e t \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e R E D I S - P A S S W O R D - - v a l u e $ R E D I S _ P A S S W O R D \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e D O M A I N - N A M E - - v a l u e $ D O M A I N _ N A M E \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e L I V E K I T - T U R N - D O M A I N - N A M E - - v a l u e $ L I V E K I T _ T U R N _ D O M A I N _ N A M E \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e O P E N V I D U - R T C - E N G I N E - - v a l u e $ O P E N V I D U _ R T C _ E N G I N E \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e O P E N V I D U - P R O - L I C E N S E - - v a l u e $ O P E N V I D U _ P R O _ L I C E N S E \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e M O N G O - A D M I N - U S E R N A M E - - v a l u e $ M O N G O _ A D M I N _ U S E R N A M E \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e M O N G O - A D M I N - P A S S W O R D - - v a l u e $ M O N G O _ A D M I N _ P A S S W O R D \ n a z k e y v a u l t s e c r e t s e t - - v a u l t - n a m e $ { k e y V a u l t N a m e } - - n a m e M O N G O - R E P L I C A - S E T - K E Y - - v a l u e $ M O N G O _ R E P L I C A _ S E T _ K E Y \ n a z k e y v a u l t s e c r e t s e t - -
2025-04-22 11:46:24 +02:00
"get_value_from_configScriptMaster" : "#!/bin/bash\nset -e\n\n# Function to get the value of a given key from the environment file\nget_value() {\n local key=\"$1\"\n local file_path=\"$2\"\n\n # Use grep to find the line with the key, ignoring lines starting with #\n # Use awk to split on '=' and print the second field, which is the value\n local value=$(grep -E \"^\\s*$key\\s*=\" \"$file_path\" | awk -F= '{print $2}' | sed 's/#.*//; s/^\\s*//; s/\\s*$//')\n\n # If the value is empty, return \"none\"\n if [ -z \"$value\" ]; then\n echo \"none\"\n else\n echo \"$value\"\n fi\n}\n\n# Check if the correct number of arguments are supplied\nif [ \"$#\" -ne 2 ]; then\n echo \"Usage: $0 <key> <file_path>\"\n exit 1\nfi\n\n# Get the key and file path from the arguments\nkey=\"$1\"\nfile_path=\"$2\"\n\n# Get and print the value\nget_value \"$key\" \"$file_path\"\n" ,
"store_secretScriptTemplateMaster" : "#!/bin/bash\nset -e\n\naz login --identity --allow-no-subscriptions > /dev/null\n\n# Modes: save, generate\n# save mode: save the secret in the secret manager\n# generate mode: generate a random password and save it in the secret manager\nMODE=\"$1\"\n\nif [[ \"$MODE\" == \"generate\" ]]; then\n SECRET_KEY_NAME=\"$2\"\n PREFIX=\"${3:-}\"\n LENGTH=\"${4:-44}\"\n RANDOM_PASSWORD=\"$(openssl rand -base64 64 | tr -d '+/=\\n' | cut -c -${LENGTH})\"\n RANDOM_PASSWORD=\"${PREFIX}${RANDOM_PASSWORD}\"\n az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $RANDOM_PASSWORD > /dev/null\n if [[ $? -ne 0 ]]; then\n echo \"Error generating secret\"\n fi\n echo \"$RANDOM_PASSWORD\"\nelif [[ \"$MODE\" == \"save\" ]]; then\n SECRET_KEY_NAME=\"$2\"\n SECRET_VALUE=\"$3\"\n az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $SECRET_VALUE > /dev/null\n if [[ $? -ne 0 ]]; then\n echo \"Error generating secret\"\n fi\n echo \"$SECRET_VALUE\"\nelse\n exit 1\nfi\n" ,
"check_app_readyScriptMaster" : "#!/bin/bash\nset -e\nwhile true; do\n HTTP_STATUS=$(curl -Ik http://localhost:7880/twirp/health | head -n1 | awk '{print $2}')\n if [ $HTTP_STATUS == 200 ]; then\n break\n fi\n sleep 5\ndone\n" ,
"restartScriptMaster" : "#!/bin/bash\nset -e\n# Stop all services\nsystemctl stop openvidu\n\n# Update config from secret\n/usr/local/bin/update_config_from_secret.sh\n\n# Start all services\nsystemctl start openvidu\n" ,
2025-05-13 11:01:22 +02:00
"config_blobStorageTemplate" : "#!/bin/bash\nset -e\n\n# Install dir and config dir\nINSTALL_DIR=\"/opt/openvidu\"\nCLUSTER_CONFIG_DIR=\"${INSTALL_DIR}/config/cluster\"\n\naz login --identity\n\n# Config azure blob storage\nAZURE_ACCOUNT_NAME=\"${storageAccountName}\"\nAZURE_ACCOUNT_KEY=$(az storage account keys list --account-name ${storageAccountName} --query '[0].value' -o tsv)\nAZURE_CONTAINER_NAME=\"${storageAccountContainerName}\"\n\nsed -i \"s|AZURE_ACCOUNT_NAME=.*|AZURE_ACCOUNT_NAME=$AZURE_ACCOUNT_NAME|\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nsed -i \"s|AZURE_ACCOUNT_KEY=.*|AZURE_ACCOUNT_KEY=$AZURE_ACCOUNT_KEY|\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nsed -i \"s|AZURE_CONTAINER_NAME=.*|AZURE_CONTAINER_NAME=$AZURE_CONTAINER_NAME|\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\n" ,
2025-04-22 11:46:24 +02:00
"base64get_value_from_configMaster" : "[base64(variables('get_value_from_configScriptMaster'))]" ,
"base64check_app_readyMaster" : "[base64(variables('check_app_readyScriptMaster'))]" ,
"base64restartMaster" : "[base64(variables('restartScriptMaster'))]" ,
2025-05-06 09:03:55 +02:00
"userDataTemplateMasterNode" : "#!/bin/bash -x\nset -eu -o pipefail\n\n# Introduce the scripts in the instance\n# install.sh\necho ${base64install} | base64 -d > /usr/local/bin/install.sh\nchmod +x /usr/local/bin/install.sh\n\n# after_install.sh\necho ${base64after_install} | base64 -d > /usr/local/bin/after_install.sh\nchmod +x /usr/local/bin/after_install.sh\n\n# update_config_from_secret.sh\necho ${base64update_config_from_secret} | base64 -d > /usr/local/bin/update_config_from_secret.sh\nchmod +x /usr/local/bin/update_config_from_secret.sh\n\n# update_secret_from_config.sh\necho ${base64update_secret_from_config} | base64 -d > /usr/local/bin/update_secret_from_config.sh\nchmod +x /usr/local/bin/update_secret_from_config.sh\n\n# get_value_from_config.sh\necho ${base64get_value_from_config} | base64 -d > /usr/local/bin/get_value_from_config.sh\nchmod +x /usr/local/bin/get_value_from_config.sh\n\n# store_secret.sh\necho ${base64store_secret} | base64 -d > /usr/local/bin/store_secret.sh\nchmod +x /usr/local/bin/store_secret.sh\n\n# check_app_ready.sh\necho ${base64check_app_ready} | base64 -d > /usr/local/bin/check_app_ready.sh\nchmod +x /usr/local/bin/check_app_ready.sh\n\n# restart.sh\necho ${base64restart} | base64 -d > /usr/local/bin/restart.sh\nchmod +x /usr/local/bin/restart.sh\n\necho ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage.sh\nchmod +x /usr/local/bin/config_blobStorage.sh\n\n# Install azure cli\ncurl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash\n\naz login --identity --allow-no-subscriptions\n\napt-get update && apt-get install -y\n\nexport HOME=\"/root\"\n\n# Install OpenVidu\n/usr/local/bin/install.sh || { echo \"[OpenVidu] error installing OpenVidu\"; exit 1; }\n\n#Config blob storage\n/usr/local/bin/config_blobStorage.sh || { echo \"[OpenVidu] error configuring Blob Storage\"; exit 1; }\n\n# Start OpenVidu\nsystemctl start openvidu || { echo \"[OpenVidu] error starting OpenVidu\"; exit 1; }\n\n# Update shared secret\n/usr/local/bin/after_install.sh || { echo \"[OpenVidu] error updating shared secret\"; exit 1; }\n\n# Launch on reboot\necho \"@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log\" 2>&1 | crontab\n\nset +e\naz storage blob upload --account-name ${storageAccountName} --container-name automation-locks --name lock.txt --file /dev/null --auth-mode key\nset -e\n\naz keyvault secret set --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --value \"true\"\n\n# Wait for the app\nsleep 150\n/usr/local/bin/check_app_ready.sh\n" ,
2025-06-10 11:08:55 +02:00
"installScriptTemplateMedia" : "#!/bin/bash -x\nset -e\nDOMAIN=\n\n# Install dependencies\napt-get update && apt-get install -y \\\n curl \\\n unzip \\\n jq \\\n wget\n\n# Get own private IP\nPRIVATE_IP=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text\")\n\nWAIT_INTERVAL=1\nMAX_WAIT=200\nELAPSED_TIME=0\nset +e\nwhile true; do\n # get secret value\n FINISH_MASTER_NODE=$(az keyvault secret show --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --query value -o tsv)\n\n # Check if the secret has been generated\n if [ \"$FINISH_MASTER_NODE\" == \"true\" ]; then\n break\n fi\n\n ELAPSED_TIME=$((ELAPSED_TIME + WAIT_INTERVAL))\n\n # Check if the maximum waiting time has been reached\n if [ $ELAPSED_TIME -ge $MAX_WAIT ]; then\n exit 1\n fi\n\n sleep $WAIT_INTERVAL\ndone\nset -e\n# Get current shared secret\nDOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)\nOPENVIDU_PRO_LICENSE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --query value -o tsv)\nREDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)\nENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)\nOPENVIDU_VERSION=\"$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)\"\n\n# Get Master Node private IP\nMASTER_NODE_IP=${privateIPMasterNode}\n\n# Base command\nINSTALL_COMMAND=\"sh <(curl -fsSL http://get.openvidu.io/pro/elastic/$OPENVIDU_VERSION/install_ov_media_node.sh)\"\n\n# Common arguments\nCOMMON_ARGS=(\n \"--no-tty\"\n \"--install\"\n \"--environment=azure\"\n \"--deployment-type=elastic\"\n \"--node-role='media-node'\"\n \"--master-node-private-ip=$MASTER_NODE_IP\"\n \"--private-ip=$PRIVATE_IP\"\n \"--enabled-modules='$ENABLED_MODULES'\"\n \"--redis-password=$REDIS_PASSWORD\"\n)\n# Construct the final command with all arguments\nFINAL_COMMAND=\"$INSTALL_COMMAND $(printf \"%s \" \"${COMMON_ARGS[@]}\")\"\n\n# Install OpenVidu\nexec bash -c \"$FINAL_COMMAND\"\n" ,
2025-04-22 11:46:24 +02:00
"stopMediaNodeParams" : {
"subscriptionId" : "[subscription().subscriptionId]" ,
"resourceGroupName" : "[resourceGroup().name]" ,
"vmScaleSetName" : "[format('{0}-mediaNodeScaleSet', parameters('stackName'))]" ,
2025-05-13 11:59:15 +02:00
"storageAccountName" : "[if(variables('isEmptyStorageAccountName'), uniqueString(resourceGroup().id), parameters('storageAccountName'))]"
2025-04-22 11:46:24 +02:00
} ,
2025-06-25 19:03:01 +02:00
"stop_media_nodesScriptMediaTemplate" : "#!/bin/bash\nset -e\n\nif ! (set -o noclobber ; echo > /tmp/global.lock) ; then\n exit 1 # the global.lock already exists\nfi\n\n# Execute if docker is installed\nif [ -x \"$(command -v docker)\" ]; then\n\n echo \"Stopping media node services and waiting for termination...\"\n docker container kill --signal=SIGQUIT openvidu || true\n docker container kill --signal=SIGQUIT ingress || true\n docker container kill --signal=SIGQUIT egress || true\n for agent_container in $(docker ps --filter \"label=openvidu-agent=true\" --format '{{.Names}}'); do\n docker container kill --signal=SIGQUIT \"$agent_container\"\n done\n\n # Wait for running containers to not be openvidu, ingress, egress or an openvidu agent\n while [ $(docker ps --filter \"label=openvidu-agent=true\" -q | wc -l) -gt 0 ] || \\\n [ $(docker inspect -f '{{.State.Running}}' openvidu 2>/dev/null) == \"true\" ] || \\\n [ $(docker inspect -f '{{.State.Running}}' ingress 2>/dev/null) == \"true\" ] || \\\n [ $(docker inspect -f '{{.State.Running}}' egress 2>/dev/null) == \"true\" ]; do\n echo \"Waiting for containers to stop...\"\n sleep 5\n done\nfi\n\naz login --identity\n\nRESOURCE_GROUP_NAME=${resourceGroupName}\nVM_SCALE_SET_NAME=${vmScaleSetName}\nSUBSCRIPTION_ID=${subscriptionId}\nBEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\" | jq -r '.compute.resourceId')\nINSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')\nRESOURCE_ID=/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Compute/virtualMachineScaleSets/$VM_SCALE_SET_NAME\nTIMESTAMP=$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")\n\naz tag update --resource-id $RESOURCE_ID --operation replace --tags \"STATUS\"=\"HEALTHY\" \"InstanceDeleteTime\"=\"$TIMESTAMP\" \"storageAccount\"=\"${storageAccountName}\"\n\naz vmss delete-instances --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-ids $INSTANCE_ID\n" ,
2025-06-10 10:56:50 +02:00
"delete_mediaNode_ScriptMediaTemplate" : "#!/bin/bash\nset -e\n\naz login --identity\n\nRESOURCE_GROUP_NAME=${resourceGroupName}\nVM_SCALE_SET_NAME=${vmScaleSetName}\nBEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\" | jq -r '.compute.resourceId')\nINSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')\n\n\naz vmss delete-instances --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-ids $INSTANCE_ID\n" ,
"userDataMediaNodeTemplate" : "#!/bin/bash -x\nset -eu -o pipefail\n\n# Introduce the scripts in the instance\n# install.sh\necho ${base64install} | base64 -d > /usr/local/bin/install.sh\nchmod +x /usr/local/bin/install.sh\n\n# stop_media_nodes.sh\necho ${base64stop} | base64 -d > /usr/local/bin/stop_media_node.sh\nchmod +x /usr/local/bin/stop_media_node.sh\n\n# delete_media_node.sh\necho ${base64delete} | base64 -d > /usr/local/bin/delete_media_node.sh\nchmod +x /usr/local/bin/delete_media_node.sh\n\napt-get update && apt-get install -y\napt-get install -y jq\n\n# Install azure cli\ncurl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash\n\naz login --identity\n\n# Protect from scale in actions\nRESOURCE_GROUP_NAME=${resourceGroupName}\nVM_SCALE_SET_NAME=${vmScaleSetName}\nBEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\" | jq -r '.compute.resourceId')\nINSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')\naz vmss update --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-id $INSTANCE_ID --protect-from-scale-in true\n\nexport HOME=\"/root\"\n\n# Install OpenVidu\n/usr/local/bin/install.sh || { echo \"[OpenVidu] error installing OpenVidu\"; /usr/local/bin/delete_media_node.sh; }\n\n# Start OpenVidu\nsystemctl start openvidu || { echo \"[OpenVidu] error starting OpenVidu\"; /usr/local/bin/delete_media_node.sh; }\n" ,
2025-04-22 11:46:24 +02:00
"stop_media_nodesScriptMedia" : "[reduce(items(variables('stopMediaNodeParams')), createObject('value', variables('stop_media_nodesScriptMediaTemplate')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]" ,
2025-04-23 13:26:33 +02:00
"base64stopMediaNode" : "[base64(variables('stop_media_nodesScriptMedia'))]" ,
2025-06-10 10:56:50 +02:00
"delete_mediaNode_ScriptMedia" : "[reduce(items(variables('stopMediaNodeParams')), createObject('value', variables('delete_mediaNode_ScriptMediaTemplate')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]" ,
"base64delete_mediaNode_ScriptMedia" : "[base64(variables('delete_mediaNode_ScriptMedia'))]" ,
2025-05-27 11:18:05 +02:00
"isEmptyAutomationAccountName" : "[equals(parameters('automationAccountName'), '')]" ,
2025-05-23 13:53:24 +02:00
"ipExists" : "[equals(parameters('publicIpAddressObject').newOrExistingOrNone, 'existing')]" ,
"ipNew" : "[equals(parameters('publicIpAddressObject').newOrExistingOrNone, 'new')]" ,
2025-05-13 11:01:22 +02:00
"isEmptyStorageAccountName" : "[equals(parameters('storageAccountName'), '')]" ,
2025-04-23 13:26:33 +02:00
"isEmptyContainerName" : "[equals(parameters('containerName'), '')]"
2025-04-22 11:46:24 +02:00
} ,
"resources" : [
{
"type" : "Microsoft.KeyVault/vaults" ,
"apiVersion" : "2023-07-01" ,
"name" : "[variables('keyVaultName')]" ,
"location" : "[variables('location')]" ,
"properties" : {
"enabledForDeployment" : true ,
"enabledForDiskEncryption" : false ,
"enabledForTemplateDeployment" : true ,
"tenantId" : "[variables('tenantId')]" ,
"enableSoftDelete" : false ,
"accessPolicies" : [
{
"objectId" : "[reference(resourceId('Microsoft.Compute/virtualMachines', variables('masterNodeVMSettings').vmName), '2023-09-01', 'full').identity.principalId]" ,
"tenantId" : "[variables('tenantId')]" ,
"permissions" : {
"secrets" : [
"get" ,
"set" ,
"list"
]
}
} ,
{
"objectId" : "[reference(resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName'))), '2024-07-01', 'full').identity.principalId]" ,
"tenantId" : "[variables('tenantId')]" ,
"permissions" : {
"secrets" : [
"get"
]
}
} ,
{
"objectId" : "[variables('deploymentUser')]" ,
"tenantId" : "[variables('tenantId')]" ,
"permissions" : {
"secrets" : [
"get" ,
"list" ,
"set" ,
"delete" ,
"recover" ,
"backup" ,
"restore"
]
}
}
] ,
"sku" : {
"name" : "standard" ,
"family" : "A"
} ,
"networkAcls" : {
"defaultAction" : "Allow" ,
"bypass" : "AzureServices"
}
} ,
"dependsOn" : [
"[resourceId('Microsoft.Compute/virtualMachines', variables('masterNodeVMSettings').vmName)]" ,
"[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Compute/virtualMachines" ,
"apiVersion" : "2023-09-01" ,
"name" : "[variables('masterNodeVMSettings').vmName]" ,
"location" : "[variables('location')]" ,
"identity" : {
"type" : "SystemAssigned"
} ,
"properties" : {
"hardwareProfile" : {
"vmSize" : "[parameters('masterNodeInstanceType')]"
} ,
"storageProfile" : {
"osDisk" : {
"createOption" : "FromImage" ,
"managedDisk" : {
"storageAccountType" : "[variables('masterNodeVMSettings').osDiskType]"
} ,
"diskSizeGB" : 100
} ,
"imageReference" : "[variables('masterNodeVMSettings').ubuntuOSVersion]"
} ,
"networkProfile" : {
"networkInterfaces" : [
{
"id" : "[resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNoderNetInterface', parameters('stackName')))]"
}
]
} ,
"osProfile" : {
"computerName" : "[variables('masterNodeVMSettings').vmName]" ,
"adminUsername" : "[parameters('adminUsername')]" ,
"linuxConfiguration" : "[variables('masterNodeVMSettings').linuxConfiguration]"
} ,
2025-06-18 16:26:50 +02:00
"userData" : " [ b a s e 64 ( r e d u c e ( i t e m s ( c r e a t e O b j e c t ( ' b a s e 64 i n s t a l l ' , b a s e 64 ( r e d u c e ( i t e m s ( c r e a t e O b j e c t ( ' d o m a i n N a m e ' , p a r a m e t e r s ( ' d o m a i n N a m e ' ) , ' f q d n ' , i f ( v a r i a b l e s ( ' i s E m p t y I p ' ) , r e f e r e n c e ( r e s o u r c e I d ( ' M i c r o s o f t . N e t w o r k / p u b l i c I P A d d r e s s e s ' , f o r m a t ( ' { 0 } - p u b l i c I P ' , p a r a m e t e r s ( ' s t a c k N a m e ' ) ) ) , ' 2023 -11 -0 1 ' ) . d n s S e t t i n g s . f q d n , p a r a m e t e r s ( ' d o m a i n N a m e ' ) ) , ' t u r n D o m a i n N a m e ' , p a r a m e t e r s ( ' t u r n D o m a i n N a m e ' ) , ' c e r t i f i c a t e T y p e ' , p a r a m e t e r s ( ' c e r t i f i c a t e T y p e ' ) , ' l e t s E n c r y p t E m a i l ' , p a r a m e t e r s ( ' l e t s E n c r y p t E m a i l ' ) , ' o w n P u b l i c C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P u b l i c C e r t i f i c a t e ' ) , ' o w n P r i v a t e C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P r i v a t e C e r t i f i c a t e ' ) , ' t u r n O w n P u b l i c C e r t i f i c a t e ' , p a r a m e t e r s ( ' t u r n O w n P u b l i c C e r t i f i c a t e ' ) , ' t u r n O w n P r i v a t e C e r t i f i c a t e ' , p a r a m e t e r s ( ' t u r n O w n P r i v a t e C e r t i f i c a t e ' ) , ' o p e n v i d u L i c e n s e ' , p a r a m e t e r s ( ' o p e n v i d u L i c e n s e ' ) , ' r t c E n g i n e ' , p a r a m e t e r s ( ' r t c E n g i n e ' ) , ' k e y V a u l t N a m e ' , v a r i a b l e s ( ' k e y V a u l t N a m e ' ) , ' a d d i t i o n a l I n s t a l l F l a g s ' , p a r a m e t e r s ( ' a d d i t i o n a l I n s t a l l F l a g s ' ) ) ) , c r e a t e O b j e c t ( ' v a l u e ' , v a r i a b l e s ( ' i n s t a l l S c r i p t T e m p l a t e M a s t e r ' ) ) , l a m b d a ( ' c u r r ' , ' n e x t ' , c r e a t e O b j e c t ( ' v a l u e ' , r e p l a c e ( l a m b d a V a r i a b l e s ( ' c u r r ' ) . v a l u e , f o r m a t ( ' $ { { { 0 } } } ' , l a m b d a V a r i a b l e s ( ' n e x t ' ) . k e y ) , l a m b d a V a r i a b l e s ( ' n e x t ' ) . v a l u e ) ) ) ) . v a l u e ) , ' b a s e 64 a f t e r _ i n s t a l l ' , b a s e 64 ( r e d u c e ( i t e m s ( c r e a t e O b j e c t ( ' d o m a i n N a m e ' , p a r a m e t e r s ( ' d o m a i n N a m e ' ) , ' f q d n ' , i f ( v a r i a b l e s ( ' i s E m p t y I p ' ) , r e f e r e n c e ( r e s o u r c e I d ( ' M i c r o s o f t . N e t w o r k / p u b l i c I P A d d r e s s e s ' , f o r m a t ( ' { 0 } - p u b l i c I P ' , p a r a m e t e r s ( ' s t a c k N a m e ' ) ) ) , ' 2023 -11 -0 1 ' ) . d n s S e t t i n g s . f q d n , p a r a m e t e r s ( ' d o m a i n N a m e ' ) ) , ' t u r n D o m a i n N a m e ' , p a r a m e t e r s ( ' t u r n D o m a i n N a m e ' ) , ' c e r t i f i c a t e T y p e ' , p a r a m e t e r s ( ' c e r t i f i c a t e T y p e ' ) , ' l e t s E n c r y p t E m a i l ' , p a r a m e t e r s ( ' l e t s E n c r y p t E m a i l ' ) , ' o w n P u b l i c C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P u b l i c C e r t i f i c a t e ' ) , ' o w n P r i v a t e C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P r i v a t e C e r t i f i c a t e ' ) , ' t u r n O w n P u b l i c C e r t i f i c a t e ' , p a r a m e t e r s ( ' t u r n O w n P u b l i c C e r t i f i c a t e ' ) , ' t u r n O w n P r i v a t e C e r t i f i c a t e ' , p a r a m e t e r s ( ' t u r n O w n P r i v a t e C e r t i f i c a t e ' ) , ' o p e n v i d u L i c e n s e ' , p a r a m e t e r s ( ' o p e n v i d u L i c e n s e ' ) , ' r t c E n g i n e ' , p a r a m e t e r s ( ' r t c E n g i n e ' ) , ' k e y V a u l t N a m e ' , v a r i a b l e s ( ' k e y V a u l t N a m e ' ) , ' a d d i t i o n a l I n s t a l l F l a g s ' , p a r a m e t e r s ( ' a d d i t i o n a l I n s t a l l F l a g s ' ) ) ) , c r e a t e O b j e c t ( ' v a l u e ' , v a r i a b l e s ( ' a f t e r _ i n s t a l l S c r i p t T e m p l a t e M a s t e r ' ) ) , l a m b d a ( ' c u r r ' , ' n e x t ' , c r e a t e O b j e c t ( ' v a l u e ' , r e p l a c e ( l a m b d a V a r i a b l e s ( ' c u r r ' ) . v a l u e , f o r m a t ( ' $ { { { 0 } } } ' , l a m b d a V a r i a b l e s ( ' n e x t ' ) . k e y ) , l a m b d a V a r i a b l e s ( ' n e x t ' ) . v a l u e ) ) ) ) . v a l u e ) , ' b a s e 64 u p d a t e _ c o n f i g _ f r o m _ s e c r e t ' , b a s e 64 ( r e d u c e ( i t e m s ( c r e a t e O b j e c t ( ' d o m a i n N a m e ' , p a r a m e t e r s ( ' d o m a i n N a m e ' ) , ' f q d n ' , i f ( v a r i a b l e s ( ' i s E m p t y I p ' ) , r e f e r e n c e ( r e s o u r c e I d ( ' M i c r o s o f t . N e t w o r k / p u b l i c I P A d d r e s s e s ' , f o r m a t ( ' { 0 } - p u b l i c I P ' , p a r a m e t e r s ( ' s t a c k N a m e ' ) ) ) , ' 2023 -11 -0 1 ' ) . d n s S e t t i n g s . f q d n , p a r a m e t e r s ( ' d o m a i n N a m e ' ) ) , ' t u r n D o m a i n N a m e ' , p a r a m e t e r s ( ' t u r n D o m a i n N a m e ' ) , ' c e r t i f i c a t e T y p e ' , p a r a m e t e r s ( ' c e r t i f i c a t e T y p e ' ) , ' l e t s E n c r y p t E m a i l ' , p a r a m e t e r s ( ' l e t s E n c r y p t E m a i l ' ) , ' o w n P u b l i c C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P u b l i c C e r t i f i c a t e ' ) , ' o w n P r i v a t e C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P r i v a t e C e r t i f i c a t e ' ) , ' t u r n O w n P u b l i c C e r t i f i c a t e ' , p a r a m e t e r s ( ' t u r n O w n P u b l i c C e r t i f i c a t e ' ) , ' t u r n O w n P r i v a t e C e r t i f i c a t e ' , p a r a m e t e r s ( ' t u r n O w n P r i v a t e C e r t i f i c a t e ' ) , ' o p e n v i d u L i c e n s e ' , p a r a m e t e r s ( ' o p e n v i d u L i c e n s e ' ) , ' r t c E n g i n e ' , p a r a m e t e r s ( ' r t c E n g i n e ' ) , ' k e y V a u l t N a m e ' , v a r i a b l e s ( ' k e y V a u l t N a m e ' ) , ' a d d i t i o n a l I n s t a l l F l a g s ' , p a r a m e t e r s ( ' a d d i t i o n a l I n s t a l l F l a g s ' ) ) ) , c r e a t e O b j e c t ( ' v a l u e ' , v a r i a b l e s ( ' u p d a t e _ c o n f i g _ f r o m _ s e c r e t S c r i p t T e m p l a t e M a s t e r ' ) ) , l a m b d a ( ' c u r r ' , ' n e x t ' , c r e a t e O b j e c t ( ' v a l u e ' , r e p l a c e ( l a m b d a V a r i a b l e s ( ' c u r r ' ) . v a l u e , f o r m a t ( ' $ { { { 0 } } } ' , l a m b d a V a r i a b l e s ( ' n e x t ' ) . k e y ) , l a m b d a V a r i a b l e s ( ' n e x t ' ) . v a l u e ) ) ) ) . v a l u e ) , ' b a s e 64 u p d a t e _ s e c r e t _ f r o m _ c o n f i g ' , b a s e 64 ( r e d u c e ( i t e m s ( c r e a t e O b j e c t ( ' d o m a i n N a m e ' , p a r a m e t e r s ( ' d o m a i n N a m e ' ) , ' f q d n ' , i f ( v a r i a b l e s ( ' i s E m p t y I p ' ) , r e f e r e n c e ( r e s o u r c e I d ( ' M i c r o s o f t . N e t w o r k / p u b l i c I P A d d r e s s e s ' , f o r m a t ( ' { 0 } - p u b l i c I P ' , p a r a m e t e r s ( ' s t a c k N a m e ' ) ) ) , ' 2023 -11 -0 1 ' ) . d n s S e t t i n g s . f q d n , p a r a m e t e r s ( ' d o m a i n N a m e ' ) ) , ' t u r n D o m a i n N a m e ' , p a r a m e t e r s ( ' t u r n D o m a i n N a m e ' ) , ' c e r t i f i c a t e T y p e ' , p a r a m e t e r s ( ' c e r t i f i c a t e T y p e ' ) , ' l e t s E n c r y p t E m a i l ' , p a r a m e t e r s ( ' l e t s E n c r y p t E m a i l ' ) , ' o w n P u b l i c C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P u b l i c C e r t i f i c a t e ' ) , ' o w n P r i v a t e C e r t i f i c a t e ' , p a r a m e t e r s ( ' o w n P r i v a t e
2025-04-22 11:46:24 +02:00
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNoderNetInterface', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/publicIPAddresses', format('{0}-publicIP', parameters('stackName')))]" ,
2025-04-23 13:26:33 +02:00
"[resourceId('Microsoft.Storage/storageAccounts', uniqueString(resourceGroup().id))]"
2025-04-22 11:46:24 +02:00
]
} ,
{
"type" : "Microsoft.Compute/virtualMachineScaleSets" ,
"apiVersion" : "2024-07-01" ,
"name" : "[format('{0}-mediaNodeScaleSet', parameters('stackName'))]" ,
"location" : "[variables('location')]" ,
"tags" : {
"InstanceDeleteTime" : "[parameters('datetime')]" ,
2025-05-13 11:59:15 +02:00
"storageAccount" : "[if(variables('isEmptyStorageAccountName'), uniqueString(resourceGroup().id), parameters('storageAccountName'))]"
2025-04-22 11:46:24 +02:00
} ,
"identity" : {
"type" : "SystemAssigned"
} ,
"sku" : {
"name" : "[parameters('mediaNodeInstanceType')]" ,
"tier" : "Standard" ,
"capacity" : "[parameters('initialNumberOfMediaNodes')]"
} ,
"properties" : {
"overprovision" : true ,
"upgradePolicy" : {
"mode" : "Automatic"
} ,
"singlePlacementGroup" : true ,
"platformFaultDomainCount" : 1 ,
"virtualMachineProfile" : {
"storageProfile" : {
"osDisk" : {
"createOption" : "FromImage" ,
"managedDisk" : {
"storageAccountType" : "[variables('mediaNodeVMSettings').osDiskType]"
} ,
"diskSizeGB" : 50
} ,
"imageReference" : "[variables('mediaNodeVMSettings').ubuntuOSVersion]"
} ,
"osProfile" : {
"computerNamePrefix" : "[variables('mediaNodeVMSettings').vmName]" ,
"adminUsername" : "[parameters('adminUsername')]" ,
"linuxConfiguration" : "[variables('mediaNodeVMSettings').linuxConfiguration]"
} ,
"networkProfile" : {
"networkInterfaceConfigurations" : [
{
"name" : "[format('{0}-mediaNodeNetInterface', parameters('stackName'))]" ,
"properties" : {
"primary" : true ,
"ipConfigurations" : [
{
"name" : "ipconfigMediaNode" ,
"properties" : {
"subnet" : {
"id" : "[reference(resourceId('Microsoft.Network/virtualNetworks', variables('networkSettings').vNetName), '2023-11-01').subnets[0].id]"
} ,
"applicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"publicIPAddressConfiguration" : {
"name" : "publicIPAddressMediaNode" ,
"properties" : {
"publicIPAddressVersion" : "IPv4"
}
}
}
}
] ,
"networkSecurityGroup" : {
"id" : "[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]"
}
}
}
]
} ,
2025-06-10 10:56:50 +02:00
"userData" : "[base64(reduce(items(createObject('base64install', base64(reduce(items(createObject('privateIPMasterNode', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNoderNetInterface', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'keyVaultName', variables('keyVaultName'))), createObject('value', variables('installScriptTemplateMedia')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value), 'base64stop', variables('base64stopMediaNode'), 'base64delete', variables('base64delete_mediaNode_ScriptMedia'), 'resourceGroupName', resourceGroup().name, 'vmScaleSetName', format('{0}-mediaNodeScaleSet', parameters('stackName')))), createObject('value', variables('userDataMediaNodeTemplate')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value)]"
2025-04-22 11:46:24 +02:00
}
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNoderNetInterface', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]" ,
2025-04-23 13:26:33 +02:00
"[resourceId('Microsoft.Storage/storageAccounts', uniqueString(resourceGroup().id))]" ,
2025-04-22 11:46:24 +02:00
"[resourceId('Microsoft.Network/virtualNetworks', variables('networkSettings').vNetName)]"
]
} ,
{
"type" : "Microsoft.Insights/autoscalesettings" ,
"apiVersion" : "2022-10-01" ,
"name" : "[format('{0}-autoscaleSettings', parameters('stackName'))]" ,
"location" : "[resourceGroup().location]" ,
"properties" : {
"profiles" : [
{
"name" : "openvidu-medianode-autoscale" ,
"capacity" : {
"minimum" : "[string(parameters('minNumberOfMediaNodes'))]" ,
"maximum" : "[string(parameters('maxNumberOfMediaNodes'))]" ,
"default" : "[string(parameters('initialNumberOfMediaNodes'))]"
} ,
"rules" : [
{
"metricTrigger" : {
"metricName" : "Percentage CPU" ,
"metricNamespace" : "Microsoft.Compute/virtualMachineScaleSets" ,
"metricResourceUri" : "[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]" ,
"statistic" : "Average" ,
"operator" : "GreaterThan" ,
"threshold" : "[parameters('scaleTargetCPU')]" ,
"timeAggregation" : "Average" ,
"timeWindow" : "PT5M" ,
"timeGrain" : "PT1M"
} ,
"scaleAction" : {
"direction" : "Increase" ,
"type" : "ChangeCount" ,
"value" : "1" ,
"cooldown" : "PT5M"
}
} ,
{
"metricTrigger" : {
"metricName" : "Percentage CPU" ,
"metricNamespace" : "Microsoft.Compute/virtualMachineScaleSets" ,
"metricResourceUri" : "[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]" ,
"statistic" : "Average" ,
"operator" : "LessThan" ,
"threshold" : "[parameters('scaleTargetCPU')]" ,
"timeAggregation" : "Average" ,
"timeWindow" : "PT5M" ,
"timeGrain" : "PT1M"
} ,
"scaleAction" : {
"direction" : "Decrease" ,
"type" : "ChangeCount" ,
"value" : "1" ,
"cooldown" : "PT5M"
}
}
]
}
] ,
"enabled" : true ,
"targetResourceUri" : "[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Authorization/roleAssignments" ,
"apiVersion" : "2022-04-01" ,
"name" : "[guid(format('roleAssignmentForMasterNode{0}', variables('masterNodeVMSettings').vmName))]" ,
"properties" : {
"roleDefinitionId" : "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]" ,
"principalId" : "[reference(resourceId('Microsoft.Compute/virtualMachines', variables('masterNodeVMSettings').vmName), '2023-09-01', 'full').identity.principalId]"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Compute/virtualMachines', variables('masterNodeVMSettings').vmName)]"
]
} ,
{
"type" : "Microsoft.Authorization/roleAssignments" ,
"apiVersion" : "2022-04-01" ,
"name" : "[guid(format('roleAssignmentForScaleSet{0}', format('{0}-mediaNodeScaleSet', parameters('stackName'))))]" ,
"properties" : {
"roleDefinitionId" : "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]" ,
"principalId" : "[reference(resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName'))), '2024-07-01', 'full').identity.principalId]"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Insights/actionGroups" ,
"apiVersion" : "2023-01-01" ,
"name" : "actiongrouptest" ,
"location" : "global" ,
"properties" : {
"groupShortName" : "scaleinag" ,
"enabled" : true ,
"automationRunbookReceivers" : [
{
"name" : "scalein" ,
"useCommonAlertSchema" : false ,
"automationAccountId" : "[reference(resourceId('Microsoft.Resources/deployments', 'WebhookDeployment'), '2022-09-01').outputs.automationAccountId.value]" ,
"runbookName" : "scaleInRunbook" ,
"webhookResourceId" : "[reference(resourceId('Microsoft.Resources/deployments', 'WebhookDeployment'), '2022-09-01').outputs.webhookId.value]" ,
"isGlobalRunbook" : false ,
"serviceUri" : "[reference(resourceId('Microsoft.Resources/deployments', 'WebhookDeployment'), '2022-09-01').outputs.webhookUri.value]"
}
]
} ,
"dependsOn" : [
"[resourceId('Microsoft.Resources/deployments', 'WebhookDeployment')]"
]
} ,
{
"type" : "Microsoft.Insights/activityLogAlerts" ,
"apiVersion" : "2020-10-01" ,
"name" : "ScaleInAlertRule" ,
"location" : "global" ,
"properties" : {
"scopes" : [
"[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]"
] ,
"condition" : {
"allOf" : [
{
"field" : "category" ,
"equals" : "Administrative"
} ,
{
"field" : "operationName" ,
"equals" : "Microsoft.Compute/virtualMachineScaleSets/write"
} ,
{
"field" : "level" ,
"containsAny" : [
"error"
]
} ,
{
"field" : "status" ,
"containsAny" : [
"failed"
]
} ,
{
"field" : "caller" ,
"equals" : "42628537-ebd8-40bf-941a-dddd338e1fe9"
}
]
} ,
"actions" : {
"actionGroups" : [
{
"actionGroupId" : "[resourceId('Microsoft.Insights/actionGroups', 'actiongrouptest')]"
}
]
} ,
"enabled" : true
} ,
"dependsOn" : [
"[resourceId('Microsoft.Insights/actionGroups', 'actiongrouptest')]" ,
"[resourceId('Microsoft.Compute/virtualMachineScaleSets', format('{0}-mediaNodeScaleSet', parameters('stackName')))]"
]
} ,
{
"condition" : "[equals(variables('isEmptyIp'), true())]" ,
"type" : "Microsoft.Network/publicIPAddresses" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}-publicIP', parameters('stackName'))]" ,
"location" : "[variables('location')]" ,
"sku" : {
"name" : "Standard" ,
"tier" : "Regional"
} ,
"properties" : {
"publicIPAddressVersion" : "IPv4" ,
"publicIPAllocationMethod" : "Static" ,
"dnsSettings" : {
"domainNameLabel" : "[if(variables('isEmptyDomain'), toLower(format('{0}', parameters('stackName'))), null())]" ,
"fqdn" : "[if(variables('isEmptyDomain'), null(), parameters('domainName'))]"
}
}
} ,
{
"type" : "Microsoft.Network/virtualNetworks" ,
"apiVersion" : "2023-11-01" ,
"name" : "[variables('networkSettings').vNetName]" ,
"location" : "[variables('location')]" ,
"properties" : {
"addressSpace" : {
"addressPrefixes" : [
"[variables('networkSettings').vNetAddressPrefix]"
]
} ,
"subnets" : [
{
"name" : "subnetForMediaNodes" ,
"properties" : {
"addressPrefix" : "[variables('networkSettings').subnetAddressPrefixMedia]" ,
"privateEndpointNetworkPolicies" : "Disabled" ,
"privateLinkServiceNetworkPolicies" : "Enabled" ,
"networkSecurityGroup" : {
"id" : "[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]"
}
}
}
]
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/virtualNetworks/subnets" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', variables('networkSettings').vNetName, 'firstSubnetForMasterNodes')]" ,
"properties" : {
"addressPrefix" : "[variables('networkSettings').subnetAddressPrefixMaster1]" ,
"privateEndpointNetworkPolicies" : "Disabled" ,
"privateLinkServiceNetworkPolicies" : "Enabled"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/virtualNetworks', variables('networkSettings').vNetName)]"
]
} ,
{
"type" : "Microsoft.Network/networkInterfaces" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}-masterNoderNetInterface', parameters('stackName'))]" ,
"location" : "[variables('location')]" ,
"properties" : {
"ipConfigurations" : [
{
"name" : "primaryIPConfig" ,
"properties" : {
"privateIPAllocationMethod" : "Dynamic" ,
"subnet" : {
"id" : "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('networkSettings').vNetName, 'firstSubnetForMasterNodes')]"
} ,
"applicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"publicIPAddress" : {
2025-05-23 13:53:24 +02:00
"id" : "[if(variables('isEmptyIp'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}-publicIP', parameters('stackName'))), if(variables('ipNew'), resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIpAddressObject').name), resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIpAddressObject').name)))]" ,
2025-04-22 11:46:24 +02:00
"properties" : {
"deleteOption" : "Delete"
}
}
}
}
] ,
"networkSecurityGroup" : {
"id" : "[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]"
}
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/publicIPAddresses', format('{0}-publicIP', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('networkSettings').vNetName, 'firstSubnetForMasterNodes')]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}-masterNoderNSG', parameters('stackName'))]" ,
"location" : "[variables('location')]" ,
"properties" : {
"securityRules" : [
{
"name" : "SSH" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "22" ,
"access" : "Allow" ,
"priority" : 100 ,
"direction" : "Inbound"
}
} ,
{
"name" : "HTTP" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "80" ,
"access" : "Allow" ,
"priority" : 110 ,
"direction" : "Inbound"
}
} ,
{
"name" : "HTTPS" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "443" ,
"access" : "Allow" ,
"priority" : 120 ,
"direction" : "Inbound"
}
} ,
{
"name" : "RTMP" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "1935" ,
"access" : "Allow" ,
"priority" : 130 ,
"direction" : "Inbound"
}
} ,
{
"name" : "MinIO" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "9000" ,
"access" : "Allow" ,
"priority" : 140 ,
"direction" : "Inbound"
}
}
]
}
} ,
{
"type" : "Microsoft.Network/applicationSecurityGroups" ,
"apiVersion" : "2024-03-01" ,
"name" : "[format('{0}-masterNodeASG', parameters('stackName'))]" ,
"location" : "[variables('location')]"
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-masterNoderNSG', parameters('stackName')), 'mediaNode_to_masterNode_REDIS_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "7000" ,
"access" : "Allow" ,
"priority" : 150 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-masterNoderNSG', parameters('stackName')), 'mediaNode_to_masterNode_MINIO_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "9100" ,
"access" : "Allow" ,
"priority" : 160 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-masterNoderNSG', parameters('stackName')), 'mediaNode_to_masterNode_MONGO_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "20000" ,
"access" : "Allow" ,
"priority" : 170 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-masterNoderNSG', parameters('stackName')), 'mediaNode_to_masterNode_LOKI_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "3100" ,
"access" : "Allow" ,
"priority" : 180 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-masterNoderNSG', parameters('stackName')), 'mediaNode_to_masterNode_MIMIR_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "9009" ,
"access" : "Allow" ,
"priority" : 190 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-masterNoderNSG', parameters('stackName')), 'mediaNode_to_masterNode_V2COMPATIBILITY_WEBHOOK_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "4443" ,
"access" : "Allow" ,
"priority" : 200 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-masterNoderNSG', parameters('stackName')), 'mediaNode_to_masterNode_DEFAULTAPP_WEBHOOK_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "6080" ,
"access" : "Allow" ,
"priority" : 210 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-masterNoderNSG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}-mediaNoderNSG', parameters('stackName'))]" ,
"location" : "[variables('location')]" ,
"properties" : {
"securityRules" : [
{
"name" : "SSH" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "22" ,
"access" : "Allow" ,
"priority" : 100 ,
"direction" : "Inbound"
}
} ,
{
"name" : "TURN" ,
"properties" : {
"protocol" : "Udp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "443" ,
"access" : "Allow" ,
"priority" : 110 ,
"direction" : "Inbound"
}
} ,
{
"name" : "WebRTC_over_TCP" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "7881" ,
"access" : "Allow" ,
"priority" : 120 ,
"direction" : "Inbound"
}
} ,
{
"name" : "WebRTC_using_WHIP" ,
"properties" : {
"protocol" : "Udp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRange" : "7885" ,
"access" : "Allow" ,
"priority" : 130 ,
"direction" : "Inbound"
}
} ,
{
"name" : "WebRTC_traffic_UDP" ,
"properties" : {
"protocol" : "Udp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRanges" : [
"50000" ,
"60000"
] ,
"access" : "Allow" ,
"priority" : 140 ,
"direction" : "Inbound"
}
2025-07-11 21:33:05 +02:00
} ,
{
"name" : "WebRTC_traffic_TCP" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceAddressPrefix" : "*" ,
"sourcePortRange" : "*" ,
"destinationAddressPrefix" : "*" ,
"destinationPortRanges" : [
"50000" ,
"60000"
] ,
"access" : "Allow" ,
"priority" : 150 ,
"direction" : "Inbound"
}
2025-04-22 11:46:24 +02:00
}
]
}
} ,
{
"type" : "Microsoft.Network/applicationSecurityGroups" ,
"apiVersion" : "2024-03-01" ,
"name" : "[format('{0}-mediaNodeASG', parameters('stackName'))]" ,
"location" : "[variables('location')]"
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-mediaNoderNSG', parameters('stackName')), 'masterNode_to_mediaNode_RTMP_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "1935" ,
"access" : "Allow" ,
"priority" : 150 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-mediaNoderNSG', parameters('stackName')), 'masterNode_to_mediaNode_TURN_TLS_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "5349" ,
"access" : "Allow" ,
"priority" : 160 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-mediaNoderNSG', parameters('stackName')), 'masterNode_to_mediaNode_SERVER_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "7880" ,
"access" : "Allow" ,
"priority" : 170 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]"
]
} ,
{
"type" : "Microsoft.Network/networkSecurityGroups/securityRules" ,
"apiVersion" : "2023-11-01" ,
"name" : "[format('{0}/{1}', format('{0}-mediaNoderNSG', parameters('stackName')), 'masterNode_to_mediaNode_HTTP_WHIP_INGRESS')]" ,
"properties" : {
"protocol" : "Tcp" ,
"sourceApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]"
}
] ,
"sourcePortRange" : "*" ,
"destinationApplicationSecurityGroups" : [
{
"id" : "[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]"
}
] ,
"destinationPortRange" : "8080" ,
"access" : "Allow" ,
"priority" : 180 ,
"direction" : "Inbound"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-masterNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/applicationSecurityGroups', format('{0}-mediaNodeASG', parameters('stackName')))]" ,
"[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}-mediaNoderNSG', parameters('stackName')))]"
]
} ,
{
2025-05-13 11:01:22 +02:00
"condition" : "[equals(variables('isEmptyStorageAccountName'), true())]" ,
2025-04-22 11:46:24 +02:00
"type" : "Microsoft.Storage/storageAccounts" ,
"apiVersion" : "2023-01-01" ,
2025-04-23 13:26:33 +02:00
"name" : "[uniqueString(resourceGroup().id)]" ,
2025-04-22 11:46:24 +02:00
"location" : "[resourceGroup().location]" ,
"sku" : {
"name" : "Standard_LRS"
} ,
"kind" : "StorageV2" ,
"properties" : {
"accessTier" : "Cool" ,
"supportsHttpsTrafficOnly" : true
}
} ,
{
2025-05-13 11:01:22 +02:00
"condition" : "[equals(variables('isEmptyStorageAccountName'), true())]" ,
2025-04-22 11:46:24 +02:00
"type" : "Microsoft.Storage/storageAccounts/blobServices/containers" ,
"apiVersion" : "2023-01-01" ,
2025-04-23 13:26:33 +02:00
"name" : "[format('{0}/default/automation-locks', uniqueString(resourceGroup().id))]" ,
"properties" : {
"publicAccess" : "None"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Storage/storageAccounts', uniqueString(resourceGroup().id))]"
]
} ,
{
2025-05-13 11:01:22 +02:00
"condition" : "[equals(variables('isEmptyStorageAccountName'), true())]" ,
2025-04-23 13:26:33 +02:00
"type" : "Microsoft.Storage/storageAccounts/blobServices/containers" ,
"apiVersion" : "2023-01-01" ,
"name" : "[if(variables('isEmptyContainerName'), format('{0}/default/openvidu-appdata', uniqueString(resourceGroup().id)), format('{0}/default/{1}', uniqueString(resourceGroup().id), parameters('containerName')))]" ,
2025-04-22 11:46:24 +02:00
"properties" : {
"publicAccess" : "None"
} ,
"dependsOn" : [
2025-04-23 13:26:33 +02:00
"[resourceId('Microsoft.Storage/storageAccounts', uniqueString(resourceGroup().id))]"
2025-04-22 11:46:24 +02:00
]
} ,
{
"type" : "Microsoft.Resources/deployments" ,
"apiVersion" : "2022-09-01" ,
"name" : "WebhookDeployment" ,
"properties" : {
"expressionEvaluationOptions" : {
"scope" : "inner"
} ,
"mode" : "Incremental" ,
"parameters" : {
2025-05-27 11:18:05 +02:00
"automationAccountName" : "[if(variables('isEmptyAutomationAccountName'), createObject('value', uniqueString(resourceGroup().id, resourceId('Microsoft.Compute/virtualMachines', variables('masterNodeVMSettings').vmName))), createObject('value', parameters('automationAccountName')))]" ,
2025-04-22 11:46:24 +02:00
"runbookName" : {
"value" : "scaleInRunbook"
} ,
"webhookName" : {
"value" : "webhookForScaleIn"
} ,
"WebhookExpiryTime" : {
"value" : "2035-03-30T00:00:00Z"
} ,
"_artifactsLocation" : {
2025-04-22 12:06:04 +02:00
"value" : "https://raw.githubusercontent.com/OpenVidu/openvidu/refs/heads/master/openvidu-deployment/pro/shared/scaleInRunbook.ps1"
2025-04-22 11:46:24 +02:00
}
} ,
"template" : {
"$schema" : "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#" ,
"contentVersion" : "1.0.0.0" ,
"parameters" : {
"automationAccountName" : {
"type" : "String" ,
"metadata" : {
"description" : "Automation account name"
}
} ,
"webhookName" : {
"type" : "String" ,
"metadata" : {
"description" : "Webhook Name"
}
} ,
"runbookName" : {
"type" : "String" ,
"metadata" : {
"description" : "Runbook Name for which webhook will be created"
}
} ,
"WebhookExpiryTime" : {
"type" : "String" ,
"metadata" : {
"description" : "Webhook Expiry time"
}
} ,
"_artifactsLocation" : {
2025-04-22 12:06:04 +02:00
"defaultValue" : "https://raw.githubusercontent.com/OpenVidu/openvidu/refs/heads/master/openvidu-deployment/pro/shared/scaleInRunbook.ps1" ,
2025-04-22 11:46:24 +02:00
"type" : "String" ,
"metadata" : {
"description" : "URI to artifacts location"
}
}
} ,
"resources" : [
{
"type" : "Microsoft.Automation/automationAccounts" ,
"apiVersion" : "2020-01-13-preview" ,
"name" : "[parameters('automationAccountName')]" ,
"location" : "[resourceGroup().location]" ,
"identity" : {
"type" : "SystemAssigned"
} ,
"properties" : {
"sku" : {
"name" : "Basic"
}
} ,
"resources" : [
{
"type" : "runbooks" ,
"apiVersion" : "2018-06-30" ,
"name" : "[parameters('runbookName')]" ,
"location" : "[resourceGroup().location]" ,
"dependsOn" : [
"[parameters('automationAccountName')]"
] ,
"properties" : {
"runbookType" : "PowerShell72" ,
"logProgress" : "true" ,
"description" : "Scale In Runbook" ,
"publishContentLink" : {
"uri" : "[parameters('_artifactsLocation')]" ,
"version" : "1.0.0.0"
}
}
} ,
{
"type" : "webhooks" ,
"apiVersion" : "2018-06-30" ,
"name" : "[parameters('webhookName')]" ,
"dependsOn" : [
"[parameters('automationAccountName')]" ,
"[parameters('runbookName')]"
] ,
"properties" : {
"isEnabled" : true ,
"expiryTime" : "[parameters('WebhookExpiryTime')]" ,
"runbook" : {
"name" : "[parameters('runbookName')]"
}
}
}
]
} ,
{
"type" : "Microsoft.Authorization/roleAssignments" ,
"apiVersion" : "2022-04-01" ,
"name" : "[guid(format('roleAutomationContributorAssignmentAutomationAccount{0}', parameters('automationAccountName')))]" ,
"properties" : {
"roleDefinitionId" : "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]" ,
"principalId" : "[reference(resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName')), '2023-11-01', 'full').identity.principalId]" ,
"principalType" : "ServicePrincipal"
} ,
"dependsOn" : [
"[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]"
]
}
] ,
"outputs" : {
"webhookUri" : {
"type" : "String" ,
"value" : "[reference(parameters('webhookName')).uri]"
} ,
"automationAccountId" : {
"type" : "string" ,
"value" : "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]"
} ,
"webhookId" : {
"type" : "string" ,
"value" : "[resourceId('Microsoft.Automation/automationAccounts/webhooks', parameters('automationAccountName'), parameters('webhookName'))]"
}
}
}
2025-05-27 11:18:05 +02:00
} ,
"dependsOn" : [
"[resourceId('Microsoft.Compute/virtualMachines', variables('masterNodeVMSettings').vmName)]"
]
2025-04-22 11:46:24 +02:00
}
2025-05-23 13:53:24 +02:00
]
2025-04-22 11:46:24 +02:00
}