openvidu/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.bicep

2960 lines
93 KiB
Bicep

@description('Stack name')
param stackName string
@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.
[owncert] Valid for productions environments. If you have a FQDN, (DomainName parameter)
and an Elastic IP, you can use this option to use your own certificate.
[letsencrypt] Valid for production environments. If you have a FQDN, (DomainName parameter)
and an Elastic IP, you can use this option to generate a Let's Encrypt certificate.
''')
@allowed([
'selfsigned'
'owncert'
'letsencrypt'
])
param certificateType string = 'selfsigned'
@description('Domain name for the OpenVidu Deployment. Blank will generate default domain')
param domainName string
@description('If certificate type is \'owncert\', this parameter will be used to specify the public certificate')
param ownPublicCertificate string = ''
@description('If certificate type is \'owncert\', this parameter will be used to specify the private certificate')
param ownPrivateCertificate string = ''
@description('If certificate type is \'letsencrypt\', this email will be used for Let\'s Encrypt notifications')
param letsEncryptEmail string = ''
@description('Name of the PublicIPAddress resource in Azure when using certificateType \'owncert\' or \'letsencrypt\'')
param publicIpAddressResourceName string = ''
@description('(Optional) Domain name for the TURN server with TLS. Only needed if your users are behind restrictive firewalls')
param turnDomainName string = ''
@description('(Optional) This setting is applicable if the certificate type is set to \'owncert\' and the TurnDomainName is specified.')
param turnOwnPublicCertificate string = ''
@description('(Optional) This setting is applicable if the certificate type is set to \'owncert\' and the TurnDomainName is specified.')
param turnOwnPrivateCertificate string = ''
@description('Name of the PublicIPAddress resource in Azure when using TURN server with TLS')
param turnPublicIpAddressResourceName string = ''
@description('Visit https://openvidu.io/account')
@secure()
param openviduLicense string
@description('RTCEngine media engine to use')
@allowed([
'pion'
'mediasoup'
])
param rtcEngine string = 'pion'
@description('Specifies the EC2 instance type for your OpenVidu Master Node')
@allowed([
'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'
])
param masterNodeInstanceType string = 'Standard_B2s'
@description('Size of the disk in GB')
param masterNodesDiskSize int = 100
@description('Specifies the EC2 instance type for your OpenVidu Media Nodes')
@allowed([
'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'
])
param mediaNodeInstanceType string = 'Standard_B2s'
@description('Username for the Virtual Machine.')
param adminUsername string
@description('SSH Key for the Virtual Machine.')
@secure()
param adminSshKey string
@description('Number of initial media nodes to deploy')
param initialNumberOfMediaNodes int = 1
@description('Minimum number of media nodes to deploy')
param minNumberOfMediaNodes int = 1
@description('Maximum number of media nodes to deploy')
param maxNumberOfMediaNodes int = 5
@description('Target CPU percentage to scale up or down')
param scaleTargetCPU int = 50
/*------------------------------------------- VARIABLES AND VALIDATIONS -------------------------------------------*/
var masterNodeVMSettings = {
osDiskType: 'StandardSSD_LRS'
osDiskSize: masterNodesDiskSize
ubuntuOSVersion: {
publisher: 'Canonical'
offer: '0001-com-ubuntu-server-jammy'
sku: '22_04-lts-gen2'
version: 'latest'
}
linuxConfiguration: {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
{
path: '/home/${adminUsername}/.ssh/authorized_keys'
keyData: adminSshKey
}
]
}
}
}
var mediaNodeVMSettings = {
vmName: '${stackName}-VN-MediaNode'
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: '/home/${adminUsername}/.ssh/authorized_keys'
keyData: adminSshKey
}
]
}
}
}
var turnTLSIsEnabled = turnDomainName != ''
var fqdn = domainName
var keyVaultName = '${stackName}-keyvault'
var location = resourceGroup().location
var tenantId = subscription().tenantId
var deploymentUser = az.deployer().objectId
/*------------------------------------------- KEY VAULT -------------------------------------------*/
resource openviduSharedInfo 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: keyVaultName
location: location
properties: {
enabledForDeployment: true
enabledForDiskEncryption: false
enabledForTemplateDeployment: true
tenantId: tenantId
enableSoftDelete: false
accessPolicies: [
{
objectId: openviduMasterNode1.identity.principalId
tenantId: tenantId
permissions: {
secrets: ['get', 'set', 'list']
}
}
{
objectId: openviduMasterNode2.identity.principalId
tenantId: tenantId
permissions: {
secrets: ['get', 'set', 'list']
}
}
{
objectId: openviduMasterNode3.identity.principalId
tenantId: tenantId
permissions: {
secrets: ['get', 'set', 'list']
}
}
{
objectId: openviduMasterNode4.identity.principalId
tenantId: tenantId
permissions: {
secrets: ['get', 'set', 'list']
}
}
{
objectId: openviduScaleSetMediaNode.identity.principalId
tenantId: tenantId
permissions: {
secrets: ['get']
}
}
{
objectId: deploymentUser
tenantId: tenantId
permissions: {
secrets: ['get', 'list', 'set', 'delete', 'recover', 'backup', 'restore']
}
}
]
sku: {
name: 'standard'
family: 'A'
}
networkAcls: {
defaultAction: 'Allow'
bypass: 'AzureServices'
}
}
}
/*------------------------------------------- MASTER NODE -------------------------------------------*/
var stringInterpolationParamsMaster1 = {
domainName: domainName
turnDomainName: turnDomainName
certificateType: certificateType
letsEncryptEmail: letsEncryptEmail
ownPublicCertificate: ownPublicCertificate
ownPrivateCertificate: ownPrivateCertificate
turnOwnPublicCertificate: turnOwnPublicCertificate
turnOwnPrivateCertificate: turnOwnPrivateCertificate
fqdn: fqdn
openviduLicense: openviduLicense
rtcEngine: rtcEngine
keyVaultName: keyVaultName
masterNodeNum: '1'
}
var stringInterpolationParamsMaster2 = {
domainName: domainName
turnDomainName: turnDomainName
certificateType: certificateType
letsEncryptEmail: letsEncryptEmail
ownPublicCertificate: ownPublicCertificate
ownPrivateCertificate: ownPrivateCertificate
turnOwnPublicCertificate: turnOwnPublicCertificate
turnOwnPrivateCertificate: turnOwnPrivateCertificate
fqdn: fqdn
openviduLicense: openviduLicense
rtcEngine: rtcEngine
keyVaultName: keyVaultName
masterNodeNum: '2'
}
var stringInterpolationParamsMaster3 = {
domainName: domainName
turnDomainName: turnDomainName
certificateType: certificateType
letsEncryptEmail: letsEncryptEmail
ownPublicCertificate: ownPublicCertificate
ownPrivateCertificate: ownPrivateCertificate
turnOwnPublicCertificate: turnOwnPublicCertificate
turnOwnPrivateCertificate: turnOwnPrivateCertificate
fqdn: fqdn
openviduLicense: openviduLicense
rtcEngine: rtcEngine
keyVaultName: keyVaultName
masterNodeNum: '3'
}
var stringInterpolationParamsMaster4 = {
domainName: domainName
turnDomainName: turnDomainName
certificateType: certificateType
letsEncryptEmail: letsEncryptEmail
ownPublicCertificate: ownPublicCertificate
ownPrivateCertificate: ownPrivateCertificate
turnOwnPublicCertificate: turnOwnPublicCertificate
turnOwnPrivateCertificate: turnOwnPrivateCertificate
fqdn: fqdn
openviduLicense: openviduLicense
rtcEngine: rtcEngine
keyVaultName: keyVaultName
masterNodeNum: '4'
}
var installScriptTemplateMaster = '''
#!/bin/bash -x
set -e
OPENVIDU_VERSION=main
DOMAIN=
# Assume azure cli is installed
apt-get update && apt-get install -y \
curl \
unzip \
jq \
wget
# Configure Domain
if [[ "${domainName}" == '' ]]; then
DOMAIN=${fqdn}
else
DOMAIN=${domainName}
fi
# Wait for the keyvault availability
MAX_WAIT=100
WAIT_INTERVAL=1
ELAPSED_TIME=0
set +e
while true; do
# Check keyvault availability
az keyvault secret list --vault-name ${keyVaultName}
# If it is available, exit the loop
if [ $? -eq 0 ]; then
break
fi
# If not, wait and check again incrementing the time
ELAPSED_TIME=$((ELAPSED_TIME + WAIT_INTERVAL))
# If exceeded the maximum time, exit with error
if [ $ELAPSED_TIME -ge $MAX_WAIT ]; then
exit 1
fi
# Esperar antes de la próxima comprobación
sleep $WAIT_INTERVAL
done
set -e
MASTER_NODE_NUM=${masterNodeNum}
# Get own private IP
PRIVATE_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")
# Store current private IP
PRIVATE_IP="$(/usr/local/bin/store_secret.sh save MASTER-NODE-${masterNodeNum}-PRIVATE-IP $PRIVATE_IP)"
if [[ $MASTER_NODE_NUM -eq 1 ]] && [[ "$ALL_SECRETS_GENERATED" == "" || "$ALL_SECRETS_GENERATED" == "false" ]]; then
DOMAIN="$(/usr/local/bin/store_secret.sh save DOMAIN-NAME "${domainName}")"
if [[ -n "${turnDomainName}" ]]; then
LIVEKIT_TURN_DOMAIN_NAME="$(/usr/local/bin/store_secret.sh save LIVEKIT-TURN-DOMAIN-NAME "${turnDomainName}")"
fi
if [[ "${certificateType}" == "letsencrypt" ]]; then
LETSENCRYPT_EMAIL=$(/usr/local/bin/store_secret.sh save LETSENCRYPT-EMAIL "${letsEncryptEmail}")
fi
# Store usernames and generate random passwords
OPENVIDU_PRO_LICENSE="$(/usr/local/bin/store_secret.sh save OPENVIDU-PRO-LICENSE "${openviduLicense}")"
OPENVIDU_RTC_ENGINE="$(/usr/local/bin/store_secret.sh save OPENVIDU-RTC-ENGINE "${rtcEngine}")"
REDIS_PASSWORD="$(/usr/local/bin/store_secret.sh generate REDIS-PASSWORD)"
MONGO_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save MONGO-ADMIN-USERNAME "mongoadmin")"
MONGO_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate MONGO-ADMIN-PASSWORD)"
MONGO_REPLICA_SET_KEY="$(/usr/local/bin/store_secret.sh generate MONGO-REPLICA-SET-KEY)"
MINIO_ACCESS_KEY="$(/usr/local/bin/store_secret.sh save MINIO-ACCESS-KEY "minioadmin")"
MINIO_SECRET_KEY="$(/usr/local/bin/store_secret.sh generate MINIO-SECRET-KEY)"
DASHBOARD_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save DASHBOARD-ADMIN-USERNAME "dashboardadmin")"
DASHBOARD_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate DASHBOARD-ADMIN-PASSWORD)"
GRAFANA_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save GRAFANA-ADMIN-USERNAME "grafanaadmin")"
GRAFANA_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate GRAFANA-ADMIN-PASSWORD)"
DEFAULT_APP_USERNAME="$(/usr/local/bin/store_secret.sh save DEFAULT-APP-USERNAME "calluser")"
DEFAULT_APP_PASSWORD="$(/usr/local/bin/store_secret.sh generate DEFAULT-APP-PASSWORD)"
DEFAULT_APP_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save DEFAULT-APP-ADMIN-USERNAME "calladmin")"
DEFAULT_APP_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate DEFAULT-APP-ADMIN-PASSWORD)"
LIVEKIT_API_KEY="$(/usr/local/bin/store_secret.sh generate LIVEKIT-API-KEY "API" 12)"
LIVEKIT_API_SECRET="$(/usr/local/bin/store_secret.sh generate LIVEKIT-API-SECRET)"
OPENVIDU_VERSION="$(/usr/local/bin/store_secret.sh save OPENVIDU-VERSION "${OPENVIDU_VERSION}")"
ENABLED_MODULES="$(/usr/local/bin/store_secret.sh save ENABLED-MODULES "observability,app")"
ALL_SECRETS_GENERATED="$(/usr/local/bin/store_secret.sh save ALL-SECRETS-GENERATED "true")"
fi
while true; do
MASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv) || true
MASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv) || true
MASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv) || true
MASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv) || true
# Check if all master nodes have stored their private IPs
if [[ "$MASTER_NODE_1_PRIVATE_IP" != "" ]] &&
[[ "$MASTER_NODE_2_PRIVATE_IP" != "" ]] &&
[[ "$MASTER_NODE_3_PRIVATE_IP" != "" ]] &&
[[ "$MASTER_NODE_4_PRIVATE_IP" != "" ]]; then
break
fi
sleep 5
done
# Fetch the values in the keyvault
MASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv)
MASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv)
MASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv)
MASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv)
MASTER_NODE_PRIVATE_IP_LIST="$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP"
DOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)
if [[ -n "${turnDomainName}" ]]; then
LIVEKIT_TURN_DOMAIN_NAME=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-TURN-DOMAIN-NAME --query value -o tsv)
fi
if [[ "${certificateType}" == "letsencrypt" ]]; then
LETSENCRYPT_EMAIL=$(az keyvault secret show --vault-name ${keyVaultName} --name LETSENCRYPT-EMAIL --query value -o tsv)
fi
OPENVIDU_RTC_ENGINE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-RTC-ENGINE --query value -o tsv)
OPENVIDU_PRO_LICENSE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --query value -o tsv)
REDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)
MONGO_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-USERNAME --query value -o tsv)
MONGO_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-PASSWORD --query value -o tsv)
MONGO_REPLICA_SET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-REPLICA-SET-KEY --query value -o tsv)
DASHBOARD_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-USERNAME --query value -o tsv)
DASHBOARD_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-PASSWORD --query value -o tsv)
MINIO_ACCESS_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-ACCESS-KEY --query value -o tsv)
MINIO_SECRET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-SECRET-KEY --query value -o tsv)
GRAFANA_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-USERNAME --query value -o tsv)
GRAFANA_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-PASSWORD --query value -o tsv)
LIVEKIT_API_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-KEY --query value -o tsv)
LIVEKIT_API_SECRET=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-SECRET --query value -o tsv)
DEFAULT_APP_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-USERNAME --query value -o tsv)
DEFAULT_APP_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-PASSWORD --query value -o tsv)
DEFAULT_APP_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-USERNAME --query value -o tsv)
DEFAULT_APP_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-PASSWORD --query value -o tsv)
ENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)
# Base command
INSTALL_COMMAND="sh <(curl -fsSL http://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_master_node.sh)"
# Common arguments
COMMON_ARGS=(
"--no-tty"
"--install"
"--environment=azure"
"--deployment-type='ha'"
"--node-role='master-node'"
"--external-load-balancer"
"--internal-tls-termination"
"--master-node-private-ip-list='$MASTER_NODE_PRIVATE_IP_LIST'"
"--openvidu-pro-license='$OPENVIDU_PRO_LICENSE'"
"--domain-name='$DOMAIN'"
"--enabled-modules='$ENABLED_MODULES'"
"--rtc-engine=$OPENVIDU_RTC_ENGINE"
"--redis-password=$REDIS_PASSWORD"
"--mongo-admin-user=$MONGO_ADMIN_USERNAME"
"--mongo-admin-password=$MONGO_ADMIN_PASSWORD"
"--mongo-replica-set-key=$MONGO_REPLICA_SET_KEY"
"--minio-access-key=$MINIO_ACCESS_KEY"
"--minio-secret-key=$MINIO_SECRET_KEY"
"--dashboard-admin-user=$DASHBOARD_ADMIN_USERNAME"
"--dashboard-admin-password=$DASHBOARD_ADMIN_PASSWORD"
"--grafana-admin-user=$GRAFANA_ADMIN_USERNAME"
"--grafana-admin-password=$GRAFANA_ADMIN_PASSWORD"
"--default-app-user=$DEFAULT_APP_USERNAME"
"--default-app-password=$DEFAULT_APP_PASSWORD"
"--default-app-admin-user=$DEFAULT_APP_ADMIN_USERNAME"
"--default-app-admin-password=$DEFAULT_APP_ADMIN_PASSWORD"
"--livekit-api-key=$LIVEKIT_API_KEY"
"--livekit-api-secret=$LIVEKIT_API_SECRET"
)
if [[ $LIVEKIT_TURN_DOMAIN_NAME != "" ]]; then
COMMON_ARGS+=("--turn-domain-name=$LIVEKIT_TURN_DOMAIN_NAME}")
fi
# Certificate arguments
if [[ "${certificateType}" == "selfsigned" ]]; then
CERT_ARGS=(
"--certificate-type=selfsigned"
)
elif [[ "${certificateType}" == "letsencrypt" ]]; then
CERT_ARGS=(
"--certificate-type=letsencrypt"
"--letsencrypt-email=$LETSENCRYPT_EMAIL"
)
else
# Download owncert files
mkdir -p /tmp/owncert
wget -O /tmp/owncert/fullchain.pem ${ownPublicCertificate}
wget -O /tmp/owncert/privkey.pem ${ownPrivateCertificate}
# Convert to base64
OWN_CERT_CRT=$(base64 -w 0 /tmp/owncert/fullchain.pem)
OWN_CERT_KEY=$(base64 -w 0 /tmp/owncert/privkey.pem)
CERT_ARGS=(
"--certificate-type=owncert"
"--owncert-public-key=$OWN_CERT_CRT"
"--owncert-private-key=$OWN_CERT_KEY"
)
# Turn with TLS and own certificate
if [[ "${turnDomainName}" != '' ]]; then
# Download owncert files
mkdir -p /tmp/owncert-turn
wget -O /tmp/owncert-turn/fullchain.pem ${turnOwnPublicCertificate}
wget -O /tmp/owncert-turn/privkey.pem ${turnOwnPrivateCertificate}
# Convert to base64
OWN_CERT_CRT_TURN=$(base64 -w 0 /tmp/owncert-turn/fullchain.pem)
OWN_CERT_KEY_TURN=$(base64 -w 0 /tmp/owncert-turn/privkey.pem)
CERT_ARGS+=(
"--turn-owncert-private-key=$OWN_CERT_KEY_TURN"
"--turn-owncert-public-key=$OWN_CERT_CRT_TURN"
)
fi
fi
# Construct the final command
FINAL_COMMAND="$INSTALL_COMMAND $(printf "%s " "${COMMON_ARGS[@]}") $(printf "%s " "${CERT_ARGS[@]}")"
# Install OpenVidu
exec bash -c "$FINAL_COMMAND"
'''
var after_installScriptTemplateMaster = '''
#!/bin/bash
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Generate URLs
DOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)
DASHBOARD_URL="https://${DOMAIN}/dashboard/"
GRAFANA_URL="https://${DOMAIN}/grafana/"
MINIO_URL="https://${DOMAIN}/minio-console/"
# Update shared secret
az keyvault secret set --vault-name ${keyVaultName} --name DOMAIN-NAME --value $DOMAIN
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-URL --value $DASHBOARD_URL
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-URL --value $GRAFANA_URL
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-URL --value $MINIO_URL
az keyvault secret show --vault-name ${keyVaultName} --name MINIO-URL
if [[ $? -ne 0 ]]; then
echo "Error updating keyvault"
fi
'''
var update_config_from_secretScriptTemplateMaster = '''
#!/bin/bash
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Installation directory
INSTALL_DIR="/opt/openvidu"
CLUSTER_CONFIG_DIR="${INSTALL_DIR}/config/cluster"
MASTER_NODE_CONFIG_DIR="${INSTALL_DIR}/config/node"
# Replace DOMAIN_NAME
export DOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)
if [[ -n "$DOMAIN" ]]; then
sed -i "s/DOMAIN_NAME=.*/DOMAIN_NAME=$DOMAIN/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
else
exit 1
fi
# Replace LIVEKIT_TURN_DOMAIN_NAME
export LIVEKIT_TURN_DOMAIN_NAME=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-TURN-DOMAIN-NAME --query value -o tsv)
if [[ -n "$LIVEKIT_TURN_DOMAIN_NAME" ]]; then
sed -i "s/LIVEKIT_TURN_DOMAIN_NAME=.*/LIVEKIT_TURN_DOMAIN_NAME=$LIVEKIT_TURN_DOMAIN_NAME/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
fi
if [[ ${certificateType} == "letsencrypt" ]]; then
export LETSENCRYPT_EMAIL=$(az keyvault secret show --vault-name ${keyVaultName} --name LETSENCRYPT-EMAIL --query value -o tsv)
sed -i "s/LETSENCRYPT_EMAIL=.*/LETSENCRYPT_EMAIL=$LETSENCRYPT_EMAIL/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
fi
# Get the rest of the values
export REDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)
export OPENVIDU_RTC_ENGINE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-RTC-ENGINE --query value -o tsv)
export OPENVIDU_PRO_LICENSE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --query value -o tsv)
export MONGO_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-USERNAME --query value -o tsv)
export MONGO_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-PASSWORD --query value -o tsv)
export MONGO_REPLICA_SET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-REPLICA-SET-KEY --query value -o tsv)
export DASHBOARD_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-USERNAME --query value -o tsv)
export DASHBOARD_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-PASSWORD --query value -o tsv)
export MINIO_ACCESS_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-ACCESS-KEY --query value -o tsv)
export MINIO_SECRET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-SECRET-KEY --query value -o tsv)
export GRAFANA_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-USERNAME --query value -o tsv)
export GRAFANA_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-PASSWORD --query value -o tsv)
export LIVEKIT_API_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-KEY --query value -o tsv)
export LIVEKIT_API_SECRET=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-SECRET --query value -o tsv)
export DEFAULT_APP_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-USERNAME --query value -o tsv)
export DEFAULT_APP_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-PASSWORD --query value -o tsv)
export DEFAULT_APP_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-USERNAME --query value -o tsv)
export DEFAULT_APP_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-PASSWORD --query value -o tsv)
export ENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)
# Replace rest of the values
sed -i "s/REDIS_PASSWORD=.*/REDIS_PASSWORD=$REDIS_PASSWORD/" "${MASTER_NODE_CONFIG_DIR}/master_node.env"
sed -i "s/OPENVIDU_RTC_ENGINE=.*/OPENVIDU_RTC_ENGINE=$OPENVIDU_RTC_ENGINE/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/OPENVIDU_PRO_LICENSE=.*/OPENVIDU_PRO_LICENSE=$OPENVIDU_PRO_LICENSE/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_ADMIN_USERNAME=.*/MONGO_ADMIN_USERNAME=$MONGO_ADMIN_USERNAME/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_ADMIN_PASSWORD=.*/MONGO_ADMIN_PASSWORD=$MONGO_ADMIN_PASSWORD/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_REPLICA_SET_KEY=.*/MONGO_REPLICA_SET_KEY=$MONGO_REPLICA_SET_KEY/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/DASHBOARD_ADMIN_USERNAME=.*/DASHBOARD_ADMIN_USERNAME=$DASHBOARD_ADMIN_USERNAME/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/DASHBOARD_ADMIN_PASSWORD=.*/DASHBOARD_ADMIN_PASSWORD=$DASHBOARD_ADMIN_PASSWORD/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MINIO_ACCESS_KEY=.*/MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MINIO_SECRET_KEY=.*/MINIO_SECRET_KEY=$MINIO_SECRET_KEY/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/GRAFANA_ADMIN_USERNAME=.*/GRAFANA_ADMIN_USERNAME=$GRAFANA_ADMIN_USERNAME/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=$GRAFANA_ADMIN_PASSWORD/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/LIVEKIT_API_KEY=.*/LIVEKIT_API_KEY=$LIVEKIT_API_KEY/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/LIVEKIT_API_SECRET=.*/LIVEKIT_API_SECRET=$LIVEKIT_API_SECRET/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/CALL_USER=.*/CALL_USER=$DEFAULT_APP_USERNAME/" "${CLUSTER_CONFIG_DIR}/master_node/app.env"
sed -i "s/CALL_SECRET=.*/CALL_SECRET=$DEFAULT_APP_PASSWORD/" "${CLUSTER_CONFIG_DIR}/master_node/app.env"
sed -i "s/CALL_ADMIN_USER=.*/CALL_ADMIN_USER=$DEFAULT_APP_ADMIN_USERNAME/" "${CLUSTER_CONFIG_DIR}/master_node/app.env"
sed -i "s/CALL_ADMIN_SECRET=.*/CALL_ADMIN_SECRET=$DEFAULT_APP_ADMIN_PASSWORD/" "${CLUSTER_CONFIG_DIR}/master_node/app.env"
sed -i "s/ENABLED_MODULES=.*/ENABLED_MODULES=$ENABLED_MODULES/" "${CLUSTER_CONFIG_DIR}/openvidu.env"
# Update URLs in secret
DASHBOARD_URL="https://${DOMAIN}/dashboard/"
GRAFANA_URL="https://${DOMAIN}/grafana/"
MINIO_URL="https://${DOMAIN}/minio-console/"
# Update shared secret
az keyvault secret set --vault-name ${keyVaultName} --name DOMAIN-NAME --value $DOMAIN
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-URL --value $DASHBOARD_URL
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-URL --value $GRAFANA_URL
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-URL --value $MINIO_URL
'''
var update_secret_from_configScriptTemplateMaster = '''
#!/bin/bash
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Installation directory
INSTALL_DIR="/opt/openvidu"
CLUSTER_CONFIG_DIR="${INSTALL_DIR}/config/cluster"
MASTER_NODE_CONFIG_DIR="${INSTALL_DIR}/config/node"
if [[ ${certificateType} == "letsencrypt" ]]; then
LETSENCRYPT_EMAIL="$(/usr/local/bin/get_value_from_config.sh LETSENCRYPT_EMAIL "${CLUSTER_CONFIG_DIR}/openvidu.env")"
az keyvault secret set --vault-name ${keyVaultName} --name "LETSENCRYPT-EMAIL" --value $LETSENCRYPT_EMAIL
fi
# Get current values of the config
REDIS_PASSWORD="$(/usr/local/bin/get_value_from_config.sh REDIS_PASSWORD "${MASTER_NODE_CONFIG_DIR}/master_node.env")"
DOMAIN_NAME="$(/usr/local/bin/get_value_from_config.sh DOMAIN_NAME "${CLUSTER_CONFIG_DIR}/openvidu.env")"
LIVEKIT_TURN_DOMAIN_NAME="$(/usr/local/bin/get_value_from_config.sh LIVEKIT_TURN_DOMAIN_NAME "${CLUSTER_CONFIG_DIR}/openvidu.env")"
OPENVIDU_RTC_ENGINE="$(/usr/local/bin/get_value_from_config.sh OPENVIDU_RTC_ENGINE "${CLUSTER_CONFIG_DIR}/openvidu.env")"
OPENVIDU_PRO_LICENSE="$(/usr/local/bin/get_value_from_config.sh OPENVIDU_PRO_LICENSE "${CLUSTER_CONFIG_DIR}/openvidu.env")"
MONGO_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_USERNAME "${CLUSTER_CONFIG_DIR}/openvidu.env")"
MONGO_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_PASSWORD "${CLUSTER_CONFIG_DIR}/openvidu.env")"
MONGO_REPLICA_SET_KEY="$(/usr/local/bin/get_value_from_config.sh MONGO_REPLICA_SET_KEY "${CLUSTER_CONFIG_DIR}/openvidu.env")"
MINIO_ACCESS_KEY="$(/usr/local/bin/get_value_from_config.sh MINIO_ACCESS_KEY "${CLUSTER_CONFIG_DIR}/openvidu.env")"
MINIO_SECRET_KEY="$(/usr/local/bin/get_value_from_config.sh MINIO_SECRET_KEY "${CLUSTER_CONFIG_DIR}/openvidu.env")"
DASHBOARD_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_USERNAME "${CLUSTER_CONFIG_DIR}/openvidu.env")"
DASHBOARD_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_PASSWORD "${CLUSTER_CONFIG_DIR}/openvidu.env")"
GRAFANA_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_USERNAME "${CLUSTER_CONFIG_DIR}/openvidu.env")"
GRAFANA_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_PASSWORD "${CLUSTER_CONFIG_DIR}/openvidu.env")"
LIVEKIT_API_KEY="$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_KEY "${CLUSTER_CONFIG_DIR}/openvidu.env")"
LIVEKIT_API_SECRET="$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_SECRET "${CLUSTER_CONFIG_DIR}/openvidu.env")"
DEFAULT_APP_USERNAME="$(/usr/local/bin/get_value_from_config.sh CALL_USER "${CLUSTER_CONFIG_DIR}/master_node/app.env")"
DEFAULT_APP_PASSWORD="$(/usr/local/bin/get_value_from_config.sh CALL_SECRET "${CLUSTER_CONFIG_DIR}/master_node/app.env")"
DEFAULT_APP_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh CALL_ADMIN_USER "${CLUSTER_CONFIG_DIR}/master_node/app.env")"
DEFAULT_APP_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh CALL_ADMIN_SECRET "${CLUSTER_CONFIG_DIR}/master_node/app.env")"
ENABLED_MODULES="$(/usr/local/bin/get_value_from_config.sh ENABLED_MODULES "${CLUSTER_CONFIG_DIR}/openvidu.env")"
# Update shared secret
az keyvault secret set --vault-name ${keyVaultName} --name REDIS-PASSWORD --value $REDIS_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name DOMAIN-NAME --value $DOMAIN_NAME
az keyvault secret set --vault-name ${keyVaultName} --name LIVEKIT-TURN-DOMAIN-NAME --value $LIVEKIT_TURN_DOMAIN_NAME
az keyvault secret set --vault-name ${keyVaultName} --name OPENVIDU-RTC-ENGINE --value $OPENVIDU_RTC_ENGINE
az keyvault secret set --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --value $OPENVIDU_PRO_LICENSE
az keyvault secret set --vault-name ${keyVaultName} --name MONGO-ADMIN-USERNAME --value $MONGO_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name MONGO-ADMIN-PASSWORD --value $MONGO_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name MONGO-REPLICA-SET-KEY --value $MONGO_REPLICA_SET_KEY
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-ACCESS-KEY --value $MINIO_ACCESS_KEY
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-SECRET-KEY --value $MINIO_SECRET_KEY
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-USERNAME --value $DASHBOARD_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-PASSWORD --value $DASHBOARD_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-ADMIN-USERNAME --value $GRAFANA_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-ADMIN-PASSWORD --value $GRAFANA_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name LIVEKIT-API-KEY --value $LIVEKIT_API_KEY
az keyvault secret set --vault-name ${keyVaultName} --name LIVEKIT-API-SECRET --value $LIVEKIT_API_SECRET
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-USERNAME --value $DEFAULT_APP_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-PASSWORD --value $DEFAULT_APP_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-USERNAME --value $DEFAULT_APP_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-PASSWORD --value $DEFAULT_APP_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name ENABLED-MODULES --value $ENABLED_MODULES
'''
var get_value_from_configScriptMaster = '''
#!/bin/bash
set -e
# Function to get the value of a given key from the environment file
get_value() {
local key="$1"
local file_path="$2"
# Use grep to find the line with the key, ignoring lines starting with #
# Use awk to split on '=' and print the second field, which is the value
local value=$(grep -E "^\s*$key\s*=" "$file_path" | awk -F= '{print $2}' | sed 's/#.*//; s/^\s*//; s/\s*$//')
# If the value is empty, return "none"
if [ -z "$value" ]; then
echo "none"
else
echo "$value"
fi
}
# Check if the correct number of arguments are supplied
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <key> <file_path>"
exit 1
fi
# Get the key and file path from the arguments
key="$1"
file_path="$2"
# Get and print the value
get_value "$key" "$file_path"
'''
var store_secretScriptTemplateMaster = '''
#!/bin/bash
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Modes: save, generate
# save mode: save the secret in the secret manager
# generate mode: generate a random password and save it in the secret manager
MODE="$1"
if [[ "$MODE" == "generate" ]]; then
SECRET_KEY_NAME="$2"
PREFIX="${3:-}"
LENGTH="${4:-44}"
RANDOM_PASSWORD="$(openssl rand -base64 64 | tr -d '+/=\n' | cut -c -${LENGTH})"
RANDOM_PASSWORD="${PREFIX}${RANDOM_PASSWORD}"
az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $RANDOM_PASSWORD > /dev/null
if [[ $? -ne 0 ]]; then
echo "Error generating secret"
fi
echo "$RANDOM_PASSWORD"
elif [[ "$MODE" == "save" ]]; then
SECRET_KEY_NAME="$2"
SECRET_VALUE="$3"
az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $SECRET_VALUE > /dev/null
if [[ $? -ne 0 ]]; then
echo "Error generating secret"
fi
echo "$SECRET_VALUE"
else
exit 1
fi
'''
var check_app_readyScriptMaster = '''
#!/bin/bash
set -e
while true; do
HTTP_STATUS=$(curl -Ik http://localhost:7880/twirp/health | head -n1 | awk '{print $2}')
if [ $HTTP_STATUS == 200 ]; then
break
fi
sleep 5
done
'''
var restartScriptMaster = '''
#!/bin/bash
set -e
# Stop all services
systemctl stop openvidu
# Update config from secret
/usr/local/bin/update_config_from_secret.sh
# Start all services
systemctl start openvidu
'''
var installScriptMaster1 = reduce(
items(stringInterpolationParamsMaster1),
{ value: installScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var installScriptMaster2 = reduce(
items(stringInterpolationParamsMaster2),
{ value: installScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var installScriptMaster3 = reduce(
items(stringInterpolationParamsMaster3),
{ value: installScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var installScriptMaster4 = reduce(
items(stringInterpolationParamsMaster4),
{ value: installScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var after_installScriptMaster = reduce(
items(stringInterpolationParamsMaster1),
{ value: after_installScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var update_config_from_secretScriptMaster = reduce(
items(stringInterpolationParamsMaster1),
{ value: update_config_from_secretScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var update_secret_from_configScriptMaster = reduce(
items(stringInterpolationParamsMaster1),
{ value: update_secret_from_configScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var store_secretScriptMaster = reduce(
items(stringInterpolationParamsMaster1),
{ value: store_secretScriptTemplateMaster },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var base64installMaster1 = base64(installScriptMaster1)
var base64installMaster2 = base64(installScriptMaster2)
var base64installMaster3 = base64(installScriptMaster3)
var base64installMaster4 = base64(installScriptMaster4)
var base64after_installMaster = base64(after_installScriptMaster)
var base64update_config_from_secretMaster = base64(update_config_from_secretScriptMaster)
var base64update_secret_from_configMaster = base64(update_secret_from_configScriptMaster)
var base64get_value_from_configMaster = base64(get_value_from_configScriptMaster)
var base64store_secretMaster = base64(store_secretScriptMaster)
var base64check_app_readyMaster = base64(check_app_readyScriptMaster)
var base64restartMaster = base64(restartScriptMaster)
var userDataParamsMasterNode1 = {
base64install: base64installMaster1
base64after_install: base64after_installMaster
base64update_config_from_secret: base64update_config_from_secretMaster
base64update_secret_from_config: base64update_secret_from_configMaster
base64get_value_from_config: base64get_value_from_configMaster
base64store_secret: base64store_secretMaster
base64check_app_ready: base64check_app_readyMaster
base64restart: base64restartMaster
keyVaultName: keyVaultName
masterNodeNum: '1'
}
var userDataParamsMasterNode2 = {
base64install: base64installMaster2
base64after_install: base64after_installMaster
base64update_config_from_secret: base64update_config_from_secretMaster
base64update_secret_from_config: base64update_secret_from_configMaster
base64get_value_from_config: base64get_value_from_configMaster
base64store_secret: base64store_secretMaster
base64check_app_ready: base64check_app_readyMaster
base64restart: base64restartMaster
keyVaultName: keyVaultName
masterNodeNum: '2'
}
var userDataParamsMasterNode3 = {
base64install: base64installMaster3
base64after_install: base64after_installMaster
base64update_config_from_secret: base64update_config_from_secretMaster
base64update_secret_from_config: base64update_secret_from_configMaster
base64get_value_from_config: base64get_value_from_configMaster
base64store_secret: base64store_secretMaster
base64check_app_ready: base64check_app_readyMaster
base64restart: base64restartMaster
keyVaultName: keyVaultName
masterNodeNum: '3'
}
var userDataParamsMasterNode4 = {
base64install: base64installMaster4
base64after_install: base64after_installMaster
base64update_config_from_secret: base64update_config_from_secretMaster
base64update_secret_from_config: base64update_secret_from_configMaster
base64get_value_from_config: base64get_value_from_configMaster
base64store_secret: base64store_secretMaster
base64check_app_ready: base64check_app_readyMaster
base64restart: base64restartMaster
keyVaultName: keyVaultName
masterNodeNum: '4'
storageAccountName: storageAccount.name
}
var userDataTemplateMasterNode = '''
#!/bin/bash -x
set -eu -o pipefail
# Introduce the scripts in the instance
# install.sh
echo ${base64install} | base64 -d > /usr/local/bin/install.sh
chmod +x /usr/local/bin/install.sh
# after_install.sh
echo ${base64after_install} | base64 -d > /usr/local/bin/after_install.sh
chmod +x /usr/local/bin/after_install.sh
# update_config_from_secret.sh
echo ${base64update_config_from_secret} | base64 -d > /usr/local/bin/update_config_from_secret.sh
chmod +x /usr/local/bin/update_config_from_secret.sh
# update_secret_from_config.sh
echo ${base64update_secret_from_config} | base64 -d > /usr/local/bin/update_secret_from_config.sh
chmod +x /usr/local/bin/update_secret_from_config.sh
# get_value_from_config.sh
echo ${base64get_value_from_config} | base64 -d > /usr/local/bin/get_value_from_config.sh
chmod +x /usr/local/bin/get_value_from_config.sh
# store_secret.sh
echo ${base64store_secret} | base64 -d > /usr/local/bin/store_secret.sh
chmod +x /usr/local/bin/store_secret.sh
# check_app_ready.sh
echo ${base64check_app_ready} | base64 -d > /usr/local/bin/check_app_ready.sh
chmod +x /usr/local/bin/check_app_ready.sh
# restart.sh
echo ${base64restart} | base64 -d > /usr/local/bin/restart.sh
chmod +x /usr/local/bin/restart.sh
# Install azure cli
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
az login --identity --allow-no-subscriptions
apt-get update && apt-get install -y
export HOME="/root"
# Install OpenVidu
/usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
# Update shared secret
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Launch on reboot
echo "@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log" 2>&1 | crontab
MASTER_NODE_NUM=${masterNodeNum}
if [[ $MASTER_NODE_NUM -eq 4 ]]; then
set +e
az storage blob upload --account-name ${storageAccountName} --container-name automation-locks --name lock.txt --file /dev/null --auth-mode key
set -e
az keyvault secret set --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --value "true"
fi
# Wait for the app
sleep 150
/usr/local/bin/check_app_ready.sh
'''
var userDataMasterNode1 = reduce(
items(userDataParamsMasterNode1),
{ value: userDataTemplateMasterNode },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var userDataMasterNode2 = reduce(
items(userDataParamsMasterNode2),
{ value: userDataTemplateMasterNode },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var userDataMasterNode3 = reduce(
items(userDataParamsMasterNode3),
{ value: userDataTemplateMasterNode },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var userDataMasterNode4 = reduce(
items(userDataParamsMasterNode4),
{ value: userDataTemplateMasterNode },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
resource openviduMasterNode1 'Microsoft.Compute/virtualMachines@2023-09-01' = {
name: '${stackName}-VM-MasterNode1'
location: location
identity: { type: 'SystemAssigned' }
properties: {
hardwareProfile: {
vmSize: masterNodeInstanceType
}
storageProfile: {
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: masterNodeVMSettings.osDiskType
}
diskSizeGB: masterNodeVMSettings.osDiskSize
}
imageReference: masterNodeVMSettings.ubuntuOSVersion
}
networkProfile: {
networkInterfaces: [
{
id: netInterfaceMasterNode1.id
}
]
}
osProfile: {
computerName: '${stackName}-VM-MasterNode1'
adminUsername: adminUsername
adminPassword: adminSshKey
linuxConfiguration: masterNodeVMSettings.linuxConfiguration
}
userData: base64(userDataMasterNode1)
}
}
resource openviduMasterNode2 'Microsoft.Compute/virtualMachines@2023-09-01' = {
name: '${stackName}-VM-MasterNode2'
location: location
identity: { type: 'SystemAssigned' }
properties: {
hardwareProfile: {
vmSize: masterNodeInstanceType
}
storageProfile: {
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: masterNodeVMSettings.osDiskType
}
diskSizeGB: masterNodeVMSettings.osDiskSize
}
imageReference: masterNodeVMSettings.ubuntuOSVersion
}
networkProfile: {
networkInterfaces: [
{
id: netInterfaceMasterNode2.id
}
]
}
osProfile: {
computerName: '${stackName}-VM-MasterNode2'
adminUsername: adminUsername
adminPassword: adminSshKey
linuxConfiguration: masterNodeVMSettings.linuxConfiguration
}
userData: base64(userDataMasterNode2)
}
dependsOn: [openviduMasterNode1]
}
resource openviduMasterNode3 'Microsoft.Compute/virtualMachines@2023-09-01' = {
name: '${stackName}-VM-MasterNode3'
location: location
identity: { type: 'SystemAssigned' }
properties: {
hardwareProfile: {
vmSize: masterNodeInstanceType
}
storageProfile: {
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: masterNodeVMSettings.osDiskType
}
diskSizeGB: masterNodeVMSettings.osDiskSize
}
imageReference: masterNodeVMSettings.ubuntuOSVersion
}
networkProfile: {
networkInterfaces: [
{
id: netInterfaceMasterNode3.id
}
]
}
osProfile: {
computerName: '${stackName}-VM-MasterNode3'
adminUsername: adminUsername
adminPassword: adminSshKey
linuxConfiguration: masterNodeVMSettings.linuxConfiguration
}
userData: base64(userDataMasterNode3)
}
dependsOn: [openviduMasterNode2]
}
resource openviduMasterNode4 'Microsoft.Compute/virtualMachines@2023-09-01' = {
name: '${stackName}-VM-MasterNode4'
location: location
identity: { type: 'SystemAssigned' }
properties: {
hardwareProfile: {
vmSize: masterNodeInstanceType
}
storageProfile: {
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: masterNodeVMSettings.osDiskType
}
diskSizeGB: masterNodeVMSettings.osDiskSize
}
imageReference: masterNodeVMSettings.ubuntuOSVersion
}
networkProfile: {
networkInterfaces: [
{
id: netInterfaceMasterNode4.id
}
]
}
osProfile: {
computerName: '${stackName}-VM-MasterNode4'
adminUsername: adminUsername
adminPassword: adminSshKey
linuxConfiguration: masterNodeVMSettings.linuxConfiguration
}
userData: base64(userDataMasterNode4)
}
dependsOn: [openviduMasterNode3]
}
/*------------------------------------------- MEDIA NODES -------------------------------------------*/
var privateIPMasterNode1 = netInterfaceMasterNode1.properties.ipConfigurations[0].properties.privateIPAddress
var privateIPMasterNode2 = netInterfaceMasterNode2.properties.ipConfigurations[0].properties.privateIPAddress
var privateIPMasterNode3 = netInterfaceMasterNode3.properties.ipConfigurations[0].properties.privateIPAddress
var privateIPMasterNode4 = netInterfaceMasterNode4.properties.ipConfigurations[0].properties.privateIPAddress
var stringInterpolationParamsMedia = {
privateIPMasterNode1: privateIPMasterNode1
privateIPMasterNode2: privateIPMasterNode2
privateIPMasterNode3: privateIPMasterNode3
privateIPMasterNode4: privateIPMasterNode4
keyVaultName: keyVaultName
}
var installScriptTemplateMedia = '''
#!/bin/bash -x
DOMAIN=
# Install dependencies
apt-get update && apt-get install -y \
curl \
unzip \
jq \
wget
# Get own private IP
PRIVATE_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")
WAIT_INTERVAL=1
MAX_WAIT=10000
ELAPSED_TIME=0
set +e
while true; do
# get secret value
FINISH_MASTER_NODE=$(az keyvault secret show --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --query value -o tsv)
# Check if all master nodes finished
if [ "$FINISH_MASTER_NODE" == "true" ]; then
break
fi
ELAPSED_TIME=$((ELAPSED_TIME + WAIT_INTERVAL))
# Check if the maximum waiting time has been reached
if [ $ELAPSED_TIME -ge $MAX_WAIT ]; then
exit 1
fi
sleep $WAIT_INTERVAL
done
set -e
MASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv)
MASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv)
MASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv)
MASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv)
MASTER_NODE_PRIVATE_IP_LIST="$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP"
REDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)
ENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)
OPENVIDU_VERSION=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)
# Base command
INSTALL_COMMAND="sh <(curl -fsSL http://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_media_node.sh)"
# Common arguments
COMMON_ARGS=(
"--no-tty"
"--install"
"--environment=azure"
"--deployment-type='ha'"
"--node-role='media-node'"
"--master-node-private-ip-list=$MASTER_NODE_PRIVATE_IP_LIST"
"--private-ip=$PRIVATE_IP"
"--enabled-modules='$ENABLED_MODULES'"
"--redis-password=$REDIS_PASSWORD"
)
# Construct the final command with all arguments
FINAL_COMMAND="$INSTALL_COMMAND $(printf "%s " "${COMMON_ARGS[@]}")"
# Install OpenVidu
exec bash -c "$FINAL_COMMAND"
'''
var stopMediaNodeParams = {
subscriptionId: subscription().subscriptionId
resourceGroupName: resourceGroup().name
vmScaleSetName: '${stackName}-mediaNodeScaleSet'
storageAccountName: storageAccount.name
}
var stop_media_nodesScriptMediaTemplate = '''
#!/bin/bash
set -e
if ! (set -o noclobber ; echo > /tmp/global.lock) ; then
exit 1 # the global.lock already exists
fi
# Execute if docker is installed
if [ -x "$(command -v docker)" ]; then
echo "Stopping media node services and waiting for termination..."
docker container kill --signal=SIGINT openvidu || true
docker container kill --signal=SIGINT ingress || true
docker container kill --signal=SIGINT egress || true
# Wait for running containers to not be openvidu, ingress or egress
while [ $(docker inspect -f '{{.State.Running}}' openvidu 2>/dev/null) == "true" ] || \
[ $(docker inspect -f '{{.State.Running}}' ingress 2>/dev/null) == "true" ] || \
[ $(docker inspect -f '{{.State.Running}}' egress 2>/dev/null) == "true" ]; do
echo "Waiting for containers to stop..."
sleep 5
done
fi
az login --identity
RESOURCE_GROUP_NAME=${resourceGroupName}
VM_SCALE_SET_NAME=${vmScaleSetName}
SUBSCRIPTION_ID=${subscriptionId}
BEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | jq -r '.compute.resourceId')
INSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')
RESOURCE_ID=/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Compute/virtualMachineScaleSets/$VM_SCALE_SET_NAME
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
az tag update --resource-id $RESOURCE_ID --operation replace --tags "STATUS"="HEALTHY" "InstanceDeleteTime"="$TIMESTAMP" "storageAccount"="${storageAccountName}"
az vmss delete-instances --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-ids $INSTANCE_ID
'''
var userDataMediaNodeTemplate = '''
#!/bin/bash -x
set -eu -o pipefail
# Introduce the scripts in the instance
# install.sh
echo ${base64install} | base64 -d > /usr/local/bin/install.sh
chmod +x /usr/local/bin/install.sh
# stop_media_nodes.sh
echo ${base64stop} | base64 -d > /usr/local/bin/stop_media_node.sh
chmod +x /usr/local/bin/stop_media_node.sh
apt-get update && apt-get install -y
apt-get install -y jq
# Install azure cli
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
az login --identity
# Protect from scale in actions
RESOURCE_GROUP_NAME=${resourceGroupName}
VM_SCALE_SET_NAME=${vmScaleSetName}
BEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | jq -r '.compute.resourceId')
INSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')
az vmss update --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-id $INSTANCE_ID --protect-from-scale-in true
export HOME="/root"
# Install OpenVidu
/usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
'''
var installScriptMedia = reduce(
items(stringInterpolationParamsMedia),
{ value: installScriptTemplateMedia },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var stop_media_nodesScriptMedia = reduce(
items(stopMediaNodeParams),
{ value: stop_media_nodesScriptMediaTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var base64installMedia = base64(installScriptMedia)
var base64stopMediaNode = base64(stop_media_nodesScriptMedia)
var userDataParamsMedia = {
base64install: base64installMedia
base64stop: base64stopMediaNode
}
var userDataMediaNode = reduce(
items(userDataParamsMedia),
{ value: userDataMediaNodeTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var base64userDataMediaNode = base64(userDataMediaNode)
param datetime string = utcNow('u')
resource openviduScaleSetMediaNode 'Microsoft.Compute/virtualMachineScaleSets@2024-07-01' = {
name: '${stackName}-mediaNodeScaleSet'
location: location
tags: {
InstanceDeleteTime: datetime
storageAccount: storageAccount.name
}
identity: { type: 'SystemAssigned' }
sku: {
name: mediaNodeInstanceType
tier: 'Standard'
capacity: initialNumberOfMediaNodes
}
properties: {
overprovision: true
upgradePolicy: {
mode: 'Automatic'
}
singlePlacementGroup: true
platformFaultDomainCount: 1
virtualMachineProfile: {
storageProfile: {
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: mediaNodeVMSettings.osDiskType
}
diskSizeGB: 50
}
imageReference: mediaNodeVMSettings.ubuntuOSVersion
}
osProfile: {
computerNamePrefix: mediaNodeVMSettings.vmName
adminUsername: adminUsername
adminPassword: adminSshKey
linuxConfiguration: mediaNodeVMSettings.linuxConfiguration
}
networkProfile: {
networkInterfaceConfigurations: [
{
name: '${stackName}-mediaNodeNetInterface'
properties: {
primary: true
ipConfigurations: [
{
name: 'ipconfigMediaNode'
properties: {
subnet: {
id: vnet_OV.properties.subnets[0].id
}
applicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
publicIPAddressConfiguration: {
name: 'publicIPAddressMediaNode'
properties: {
publicIPAddressVersion: 'IPv4'
}
}
}
}
]
networkSecurityGroup: {
id: openviduMediaNodeNSG.id
}
}
}
]
}
userData: base64userDataMediaNode
}
}
}
resource openviduAutoScaleSettingsMediaNode 'Microsoft.Insights/autoscaleSettings@2022-10-01' = {
name: '${stackName}-autoscaleSettings'
location: resourceGroup().location
properties: {
profiles: [
{
name: 'openvidu-medianode-autoscale'
capacity: {
minimum: string(minNumberOfMediaNodes)
maximum: string(maxNumberOfMediaNodes)
default: string(initialNumberOfMediaNodes)
}
rules: [
{
metricTrigger: {
metricName: 'Percentage CPU'
metricNamespace: 'Microsoft.Compute/virtualMachineScaleSets'
metricResourceUri: openviduScaleSetMediaNode.id
statistic: 'Average'
operator: 'GreaterThan'
threshold: 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: openviduScaleSetMediaNode.id
statistic: 'Average'
operator: 'LessThan'
threshold: scaleTargetCPU
timeAggregation: 'Average'
timeWindow: 'PT5M'
timeGrain: 'PT1M'
}
scaleAction: {
direction: 'Decrease'
type: 'ChangeCount'
value: '1'
cooldown: 'PT5M'
}
}
]
}
]
enabled: true
targetResourceUri: openviduScaleSetMediaNode.id
}
}
/*------------------------------------------- SCALE IN ------------------------------------------*/
resource roleAssignmentMasterNode 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid('roleAssignmentForMasterNode${openviduMasterNode4.name}')
scope: resourceGroup()
properties: {
roleDefinitionId: subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
'b24988ac-6180-42a0-ab88-20f7382dd24c'
)
principalId: openviduMasterNode4.identity.principalId
}
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid('roleAssignmentForScaleSet${openviduScaleSetMediaNode.name}')
scope: resourceGroup()
properties: {
roleDefinitionId: subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
'b24988ac-6180-42a0-ab88-20f7382dd24c'
)
principalId: openviduScaleSetMediaNode.identity.principalId
}
}
@description('Automation Account Name to create a runbook inside it for scale in')
param automationAccountName string
module webhookModule '../../shared/webhookdeployment.json' = {
params: {
automationAccountName: automationAccountName
runbookName: 'scaleInRunbook'
webhookName: 'webhookForScaleIn'
WebhookExpiryTime: '2035-03-30T00:00:00Z'
_artifactsLocation: 'https://raw.githubusercontent.com/OpenVidu/openvidu/refs/heads/master/openvidu-deployment/pro/shared/scaleInRunbook.ps1'
}
name: 'WebhookDeployment'
}
resource actionGroupScaleIn 'Microsoft.Insights/actionGroups@2023-01-01' = {
name: 'actiongrouptest'
location: 'global'
properties: {
groupShortName: 'scaleinag'
enabled: true
automationRunbookReceivers: [
{
name: 'scalein'
useCommonAlertSchema: false
automationAccountId: webhookModule.outputs.automationAccountId
runbookName: 'scaleInRunbook'
webhookResourceId: webhookModule.outputs.webhookId
isGlobalRunbook: false
serviceUri: webhookModule.outputs.webhookUri
}
]
}
}
resource scaleInActivityLogRule 'Microsoft.Insights/activityLogAlerts@2020-10-01' = {
name: 'ScaleInAlertRule'
location: 'global'
properties: {
scopes: [
openviduScaleSetMediaNode.id
]
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: actionGroupScaleIn.id
}
]
}
enabled: true
}
}
/*------------------------------------------- NETWORK -------------------------------------------*/
var isEmptyIp = publicIpAddressResourceName == ''
var turnIsEmptyIp = turnPublicIpAddressResourceName == ''
var lbName = '${stackName}-loadBalancer'
var lbFrontEndName = 'LoadBalancerFrontEnd'
var lbBackendPoolNameMasterNode = 'LoadBalancerBackEndMasterNode'
resource publicIPAddressLoadBalancer 'Microsoft.Network/publicIPAddresses@2024-05-01' = if (isEmptyIp == true) {
name: '${stackName}-publicIPAddressLoadBalancer'
location: location
sku: {
name: 'Standard'
}
properties: {
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Static'
}
}
resource publicIP_LoadBalancer_ifNotEmpty 'Microsoft.Network/publicIPAddresses@2023-11-01' existing = if (!isEmptyIp == true) {
name: publicIpAddressResourceName
}
resource publicIPAddressTurnTLSLoadBalancer 'Microsoft.Network/publicIPAddresses@2024-05-01' = if (turnTLSIsEnabled == true) {
name: '${stackName}-publicIPAddressTurnTLSLoadBalancer'
location: location
sku: {
name: 'Standard'
}
properties: {
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Static'
}
}
resource publicIP_TurnTLSLoadBalancer_ifNotEmpty 'Microsoft.Network/publicIPAddresses@2023-11-01' existing = if (!turnIsEmptyIp && turnTLSIsEnabled == true) {
name: publicIpAddressResourceName
}
resource LoadBalancer 'Microsoft.Network/loadBalancers@2024-05-01' = {
name: lbName
location: location
sku: {
name: 'Standard'
}
properties: {
frontendIPConfigurations: [
{
name: lbFrontEndName
properties: {
publicIPAddress: {
id: isEmptyIp ? publicIPAddressLoadBalancer.id : publicIP_LoadBalancer_ifNotEmpty.id
}
}
}
]
backendAddressPools: [
{
name: lbBackendPoolNameMasterNode
}
]
loadBalancingRules: [
{
name: 'HTTPSRuleforMasterNode'
properties: {
frontendIPConfiguration: {
id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', lbName, lbFrontEndName)
}
backendAddressPool: {
id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', lbName, lbBackendPoolNameMasterNode)
}
frontendPort: 443
backendPort: 443
enableFloatingIP: false
protocol: 'Tcp'
enableTcpReset: true
loadDistribution: 'Default'
disableOutboundSnat: true
probe: {
id: resourceId('Microsoft.Network/loadBalancers/probes', lbName, 'probeForHTTPSRuleMasterNode')
}
}
}
{
name: 'RTMPRuleforMasterNode'
properties: {
frontendIPConfiguration: {
id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', lbName, lbFrontEndName)
}
backendAddressPool: {
id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', lbName, lbBackendPoolNameMasterNode)
}
frontendPort: 1935
backendPort: 1945
enableFloatingIP: false
protocol: 'Tcp'
enableTcpReset: true
loadDistribution: 'Default'
disableOutboundSnat: true
probe: {
id: resourceId('Microsoft.Network/loadBalancers/probes', lbName, 'probeForRTMPRuleMasterNode')
}
}
}
{
name: 'HTTPRuleforMasterNode'
properties: {
frontendIPConfiguration: {
id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', lbName, lbFrontEndName)
}
backendAddressPool: {
id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', lbName, lbBackendPoolNameMasterNode)
}
frontendPort: 80
backendPort: 80
enableFloatingIP: false
protocol: 'Tcp'
enableTcpReset: true
loadDistribution: 'Default'
disableOutboundSnat: true
probe: {
id: resourceId('Microsoft.Network/loadBalancers/probes', lbName, 'probeForHTTPSRuleMasterNode')
}
}
}
]
probes: [
{
name: 'probeForHTTPSRuleMasterNode'
properties: {
protocol: 'Http'
requestPath: '/health/caddy'
port: 7880
probeThreshold: 3
intervalInSeconds: 10
numberOfProbes: 5
}
}
{
name: 'probeForRTMPRuleMasterNode'
properties: {
protocol: 'Tcp'
port: 1945
intervalInSeconds: 5
numberOfProbes: 2
}
}
]
outboundRules: []
}
}
var tlbName = '${stackName}-loadBalancer'
var tlbFrontEndName = 'LoadBalancerFrontEnd'
resource TurnTLSLoadbalancer 'Microsoft.Network/loadBalancers@2024-05-01' = if (turnTLSIsEnabled == true) {
name: tlbName
location: location
sku: {
name: 'Standard'
}
properties: {
frontendIPConfigurations: [
{
name: tlbFrontEndName
properties: {
privateIPAllocationMethod: 'Dynamic'
privateIPAddressVersion: 'IPv4'
publicIPAddress: {
id: turnIsEmptyIp ? publicIPAddressLoadBalancer.id : publicIP_TurnTLSLoadBalancer_ifNotEmpty.id
}
}
}
]
backendAddressPools: [
{
name: lbBackendPoolNameMasterNode
}
]
loadBalancingRules: [
{
name: 'TURNTLSRuleforMasterNode'
properties: {
frontendIPConfiguration: {
id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', tlbName, tlbFrontEndName)
}
backendAddressPool: {
id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', tlbName, lbBackendPoolNameMasterNode)
}
frontendPort: 443
backendPort: 443
enableFloatingIP: false
protocol: 'Tcp'
enableTcpReset: true
loadDistribution: 'Default'
disableOutboundSnat: true
probe: {
id: resourceId('Microsoft.Network/loadBalancers/probes', tlbName, 'probeForHTTPSRuleMasterNode')
}
}
}
]
probes: [
{
name: 'probeForTURNTLSRuleMasterNode'
properties: {
protocol: 'Http'
requestPath: '/'
port: 443
probeThreshold: 3
intervalInSeconds: 10
numberOfProbes: 5
}
}
]
}
}
resource natGateway 'Microsoft.Network/natGateways@2021-05-01' = {
name: '${stackName}-natGateway'
location: location
sku: {
name: 'Standard'
}
properties: {
idleTimeoutInMinutes: 4
publicIpAddresses: [
{
id: natGatewayPublicIPAddress.id
}
]
}
}
resource natGatewayPublicIPAddress 'Microsoft.Network/publicIPAddresses@2021-05-01' = {
name: '${stackName}-publicIPnatGateway'
location: location
sku: {
name: 'Standard'
}
properties: {
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Static'
idleTimeoutInMinutes: 4
}
}
var networkSettings = {
vNetAddressPrefix: '10.0.0.0/16'
subnetAddressPrefixMaster1: '10.0.1.0/24'
subnetAddressPrefixMaster2: '10.0.2.0/24'
subnetAddressPrefixMedia: '10.0.0.0/24'
vNetName: '${stackName}-virtualNetwork'
}
resource vnet_OV 'Microsoft.Network/virtualNetworks@2023-11-01' = {
name: networkSettings.vNetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
networkSettings.vNetAddressPrefix
]
}
subnets: [
{
name: 'subnetForMediaNodes'
properties: {
addressPrefix: networkSettings.subnetAddressPrefixMedia
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
networkSecurityGroup: {
id: openviduMediaNodeNSG.id
}
}
}
]
}
}
resource subnetMasterNode1 'Microsoft.Network/virtualNetworks/subnets@2023-11-01' = {
parent: vnet_OV
name: 'firstSubnetForMasterNodes'
properties: {
addressPrefix: networkSettings.subnetAddressPrefixMaster1
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
natGateway: {
id: natGateway.id
}
}
}
resource subnetMasterNode2 'Microsoft.Network/virtualNetworks/subnets@2023-11-01' = {
parent: vnet_OV
name: 'secondSubnetForMasterNodes'
properties: {
addressPrefix: networkSettings.subnetAddressPrefixMaster2
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
natGateway: {
id: natGateway.id
}
}
}
resource netInterfaceMasterNode1 'Microsoft.Network/networkInterfaces@2023-11-01' = {
name: '${stackName}-masterNodeNetInterface1'
location: location
properties: {
ipConfigurations: [
{
name: 'primaryIPConfig'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnetMasterNode1.id
}
applicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
loadBalancerBackendAddressPools: [
{
id: LoadBalancer.properties.backendAddressPools[0].id
}
]
}
}
]
networkSecurityGroup: {
id: openviduMasterNodeNSG.id
}
}
}
resource netInterfaceMasterNode2 'Microsoft.Network/networkInterfaces@2023-11-01' = {
name: '${stackName}-masterNodeNetInterface2'
location: location
properties: {
ipConfigurations: [
{
name: 'primaryIPConfig'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnetMasterNode2.id
}
applicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
loadBalancerBackendAddressPools: [
{
id: LoadBalancer.properties.backendAddressPools[0].id
}
]
}
}
]
networkSecurityGroup: {
id: openviduMasterNodeNSG.id
}
}
}
resource netInterfaceMasterNode3 'Microsoft.Network/networkInterfaces@2023-11-01' = {
name: '${stackName}-masterNodeNetInterface3'
location: location
properties: {
ipConfigurations: [
{
name: 'primaryIPConfig'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnetMasterNode1.id
}
applicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
loadBalancerBackendAddressPools: [
{
id: LoadBalancer.properties.backendAddressPools[0].id
}
]
}
}
]
networkSecurityGroup: {
id: openviduMasterNodeNSG.id
}
}
}
resource netInterfaceMasterNode4 'Microsoft.Network/networkInterfaces@2023-11-01' = {
name: '${stackName}-masterNodeNetInterface4'
location: location
properties: {
ipConfigurations: [
{
name: 'primaryIPConfig'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnetMasterNode2.id
}
applicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
loadBalancerBackendAddressPools: [
{
id: LoadBalancer.properties.backendAddressPools[0].id
}
]
}
}
]
networkSecurityGroup: {
id: openviduMasterNodeNSG.id
}
}
}
resource openviduMasterNodeNSG 'Microsoft.Network/networkSecurityGroups@2023-11-01' = {
name: '${stackName}-masterNodeNSG'
location: location
properties: {
securityRules: [
{
name: 'SSH'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
access: 'Allow'
priority: 100
direction: 'Inbound'
}
}
{
name: 'ProbeAPI'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: 'AzureLoadBalancer'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '7880'
access: 'Allow'
priority: 500
direction: 'Inbound'
}
}
{
name: 'HTTP'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '80'
access: 'Allow'
priority: 510
direction: 'Inbound'
}
}
]
}
}
resource openviduMasterNodeASG 'Microsoft.Network/applicationSecurityGroups@2024-03-01' = {
name: '${stackName}-masterNodeASG'
location: location
}
resource loadBalancerToMasterIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'loadBalancer_to_masterNode_INGRESS'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '443'
access: 'Allow'
priority: 110
direction: 'Inbound'
}
}
resource masterToMasterRedisIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_REDIS_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '7000'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '7001'
access: 'Allow'
priority: 120
direction: 'Inbound'
}
}
resource mediaToMasterRedisIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'mediaNode_to_masterNode_REDIS_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
sourcePortRange: '7000'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '7001'
access: 'Allow'
priority: 130
direction: 'Inbound'
}
}
resource masterToMasterMinioIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_MINIO_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '9100'
access: 'Allow'
priority: 140
direction: 'Inbound'
}
}
resource masterToMasterMinioConsoleIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_MINIO_CONSOLE_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '9101'
access: 'Allow'
priority: 150
direction: 'Inbound'
}
}
resource mediaToMasterMinioIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'mediaNode_to_masterNode_MINIO_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '9100'
access: 'Allow'
priority: 160
direction: 'Inbound'
}
}
resource masterToMasterMongoIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_MONGO_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '20000'
access: 'Allow'
priority: 170
direction: 'Inbound'
}
}
resource mediaToMasterMongoIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'mediaNode_to_masterNode_MONGO_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '20000'
access: 'Allow'
priority: 180
direction: 'Inbound'
}
}
resource masterToMasterMimirGrpcIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_MIMIRGRPC_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '9095'
access: 'Allow'
priority: 190
direction: 'Inbound'
}
}
resource masterToMasterMimirGossipIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_MIMIRGOSSIP_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '7946'
access: 'Allow'
priority: 200
direction: 'Inbound'
}
}
resource mediaToMasterMimirIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'mediaNode_to_masterNode_MIMIR_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '9009'
access: 'Allow'
priority: 210
direction: 'Inbound'
}
}
resource masterToMasterLokiGrpcIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_LOKIGRPC_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '9096'
access: 'Allow'
priority: 220
direction: 'Inbound'
}
}
resource masterToMasterLokiGossipIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_LOKIGOSSIP_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '7947'
access: 'Allow'
priority: 230
direction: 'Inbound'
}
}
resource masterToMasterDashboardIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_DASHBOARD_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '5000'
access: 'Allow'
priority: 240
direction: 'Inbound'
}
}
resource masterToMasterGrafanaIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_GRAFANA_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '3000'
access: 'Allow'
priority: 250
direction: 'Inbound'
}
}
resource mediaToMasterLokiIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'mediaNode_to_masterNode_LOKI_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '3100'
access: 'Allow'
priority: 260
direction: 'Inbound'
}
}
resource masterToMasterV2CompatibilityIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_V2COMPATIBILITY_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '4443'
access: 'Allow'
priority: 270
direction: 'Inbound'
}
}
resource mediaToMasterV2CompatibilityWebhookIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'mediaNode_to_masterNode_V2COMPATIBILITY_WEBHOOK_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '4443'
access: 'Allow'
priority: 280
direction: 'Inbound'
}
}
resource masterToMasterDefaultApp 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'masterNode_to_masterNode_DEFAULTAPP_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '6080'
access: 'Allow'
priority: 290
direction: 'Inbound'
}
}
resource mediaToMasterDefaultAppWebhookIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMasterNodeNSG
name: 'mediaNode_to_masterNode_DEFAULTAPP_WEBHOOK_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
destinationPortRange: '6080'
access: 'Allow'
priority: 300
direction: 'Inbound'
}
}
resource openviduMediaNodeNSG 'Microsoft.Network/networkSecurityGroups@2023-11-01' = {
name: '${stackName}-mediaNodeNSG'
location: 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'
}
}
]
}
}
resource openviduMediaNodeASG 'Microsoft.Network/applicationSecurityGroups@2024-03-01' = {
name: '${stackName}-mediaNodeASG'
location: location
}
resource loadBalancerToMediaRtmpIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMediaNodeNSG
name: 'loadBalancer_to_mediaNode_RTMP_INGRESS'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: 'AzureLoadBalancer'
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
destinationPortRange: '1945'
access: 'Allow'
priority: 150
direction: 'Inbound'
}
}
resource loadBalancerToMediaHealthcheckIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMediaNodeNSG
name: 'loadBalancer_to_mediaNode_HEALTHCHECK_INGRESS'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: 'AzureLoadBalancer'
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
destinationPortRange: '9092'
access: 'Allow'
priority: 160
direction: 'Inbound'
}
}
resource loadBalancerToMediaTurnTlsIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = if (turnTLSIsEnabled == true) {
parent: openviduMediaNodeNSG
name: 'loadbalancer_to_mediaNode_TURN_TLS_INGRESS'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: 'AzureLoadBalancer'
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
destinationPortRange: '5349'
access: 'Allow'
priority: 170
direction: 'Inbound'
}
}
resource loadBalancerToMediaTurnTlsHealthCheckIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = if (turnTLSIsEnabled == true) {
parent: openviduMediaNodeNSG
name: 'masterNode_to_mediaNode_TURN_TLSHEALTHCHECK_INGRESS'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: 'AzureLoadBalancer'
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
destinationPortRange: '7880'
access: 'Allow'
priority: 180
direction: 'Inbound'
}
}
resource masterToMediaServerIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMediaNodeNSG
name: 'masterNode_to_mediaNode_SERVER_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
destinationPortRange: '7880'
access: 'Allow'
priority: 190
direction: 'Inbound'
}
}
resource masterToMediaClientIngress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: openviduMediaNodeNSG
name: 'masterNode_to_mediaNode_CLIENT_INGRESS'
properties: {
protocol: 'Tcp'
sourceApplicationSecurityGroups: [
{
id: openviduMasterNodeASG.id
}
]
sourcePortRange: '*'
destinationApplicationSecurityGroups: [
{
id: openviduMediaNodeASG.id
}
]
destinationPortRange: '8080'
access: 'Allow'
priority: 200
direction: 'Inbound'
}
}
/*------------------------------------------- STORAGE ACCOUNT ----------------------------------------*/
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: uniqueString(resourceGroup().id)
location: resourceGroup().location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Cool'
supportsHttpsTrafficOnly: true
}
}
resource blobContainerScaleIn 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
name: '${storageAccount.name}/default/automation-locks'
properties: {
publicAccess: 'None'
}
}
@description('Name of the bucket where OpenVidu will store the recordings. If not specified, a default bucket will be created.')
param containerName string = ''
var isEmptyContainerName = containerName == ''
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
name: isEmptyContainerName
? '${storageAccount.name}/default/openvidu-appdata'
: '${storageAccount.name}/default/${containerName}'
properties: {
publicAccess: 'None'
}
}
/*------------------------------------------- OUTPUTS -------------------------------------------*/