mirror of https://github.com/OpenVidu/openvidu.git
3050 lines
97 KiB
Bicep
3050 lines
97 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.')
|
|
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 publicIpAddressObject object
|
|
|
|
@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('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 object
|
|
|
|
@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
|
|
|
|
param additionalInstallFlags string = ''
|
|
|
|
/*------------------------------------------- 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.sshPublicKey
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
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.sshPublicKey
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
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'
|
|
additionalInstallFlags: additionalInstallFlags
|
|
}
|
|
|
|
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'
|
|
additionalInstallFlags: additionalInstallFlags
|
|
}
|
|
|
|
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'
|
|
additionalInstallFlags: additionalInstallFlags
|
|
}
|
|
|
|
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'
|
|
additionalInstallFlags: additionalInstallFlags
|
|
}
|
|
|
|
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)"
|
|
MEET_ADMIN_USER="$(/usr/local/bin/store_secret.sh save MEET-ADMIN-USER "meetadmin")"
|
|
MEET_ADMIN_SECRET="$(/usr/local/bin/store_secret.sh generate MEET-ADMIN-SECRET)"
|
|
MEET_API_KEY="$(/usr/local/bin/store_secret.sh generate MEET-API-KEY)"
|
|
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,openviduMeet,v2compatibility")"
|
|
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)
|
|
MEET_ADMIN_USER=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-ADMIN-USER --query value -o tsv)
|
|
MEET_ADMIN_SECRET=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-ADMIN-SECRET --query value -o tsv)
|
|
MEET_API_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-API-KEY --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"
|
|
"--meet-admin-user=$MEET_ADMIN_USER"
|
|
"--meet-admin-password=$MEET_ADMIN_SECRET"
|
|
"--meet-api-key=$MEET_API_KEY"
|
|
"--livekit-api-key=$LIVEKIT_API_KEY"
|
|
"--livekit-api-secret=$LIVEKIT_API_SECRET"
|
|
)
|
|
|
|
# Include additional installer flags provided by the user
|
|
if [[ "${additionalInstallFlags}" != "" ]]; then
|
|
IFS=',' read -ra EXTRA_FLAGS <<< "${additionalInstallFlags}"
|
|
for extra_flag in "${EXTRA_FLAGS[@]}"; do
|
|
# Trim whitespace around each flag
|
|
extra_flag="$(echo -e "${extra_flag}" | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//')"
|
|
if [[ "$extra_flag" != "" ]]; then
|
|
COMMON_ARGS+=("$extra_flag")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
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 MEET_ADMIN_USER=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-ADMIN-USER --query value -o tsv)
|
|
export MEET_ADMIN_SECRET=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-ADMIN-SECRET --query value -o tsv)
|
|
export MEET_API_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MEET-API-KEY --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/MEET_ADMIN_USER=.*/MEET_ADMIN_USER=$MEET_ADMIN_USER/" "${CLUSTER_CONFIG_DIR}/master_node/meet.env"
|
|
sed -i "s/MEET_ADMIN_SECRET=.*/MEET_ADMIN_SECRET=$MEET_ADMIN_SECRET/" "${CLUSTER_CONFIG_DIR}/master_node/meet.env"
|
|
sed -i "s/MEET_API_KEY=.*/MEET_API_KEY=$MEET_API_KEY/" "${CLUSTER_CONFIG_DIR}/master_node/meet.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")"
|
|
MEET_ADMIN_USER="$(/usr/local/bin/get_value_from_config.sh MEET_ADMIN_USER "${CLUSTER_CONFIG_DIR}/master_node/meet.env")"
|
|
MEET_ADMIN_SECRET="$(/usr/local/bin/get_value_from_config.sh MEET_ADMIN_SECRET "${CLUSTER_CONFIG_DIR}/master_node/meet.env")"
|
|
MEET_API_KEY="$(/usr/local/bin/get_value_from_config.sh MEET_API_KEY "${CLUSTER_CONFIG_DIR}/master_node/meet.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 MEET-ADMIN-USER --value $MEET_ADMIN_USER
|
|
az keyvault secret set --vault-name ${keyVaultName} --name MEET-ADMIN-SECRET --value $MEET_ADMIN_SECRET
|
|
az keyvault secret set --vault-name ${keyVaultName} --name MEET-API-KEY --value $MEET_API_KEY
|
|
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 config_blobStorageTemplate = '''
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
# Install dir and config dir
|
|
INSTALL_DIR="/opt/openvidu"
|
|
CLUSTER_CONFIG_DIR="${INSTALL_DIR}/config/cluster"
|
|
|
|
az login --identity
|
|
|
|
# Config azure blob storage
|
|
AZURE_ACCOUNT_NAME="${storageAccountName}"
|
|
AZURE_ACCOUNT_KEY=$(az storage account keys list --account-name ${storageAccountName} --query '[0].value' -o tsv)
|
|
AZURE_CONTAINER_NAME="${storageAccountContainerName}"
|
|
|
|
sed -i "s|AZURE_ACCOUNT_NAME=.*|AZURE_ACCOUNT_NAME=$AZURE_ACCOUNT_NAME|" "${CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s|AZURE_ACCOUNT_KEY=.*|AZURE_ACCOUNT_KEY=$AZURE_ACCOUNT_KEY|" "${CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s|AZURE_CONTAINER_NAME=.*|AZURE_CONTAINER_NAME=$AZURE_CONTAINER_NAME|" "${CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
'''
|
|
|
|
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 blobStorageParams = {
|
|
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : existingStorageAccount.name
|
|
storageAccountKey: listKeys(storageAccount.id, '2021-04-01').keys[0].value
|
|
storageAccountContainerName: isEmptyAppDataContainerName ? 'openvidu-appdata' : '${appDataContainerName}'
|
|
storageAccountClusterContainerName: isEmptyClusterContainerName
|
|
? 'openvidu-clusterdata'
|
|
: '${clusterDataContainerName}'
|
|
}
|
|
|
|
var config_blobStorageScript = reduce(
|
|
items(blobStorageParams),
|
|
{ value: config_blobStorageTemplate },
|
|
(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 base64config_blobStorage = base64(config_blobStorageScript)
|
|
|
|
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'
|
|
base64config_blobStorage: base64config_blobStorage
|
|
}
|
|
|
|
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'
|
|
base64config_blobStorage: base64config_blobStorage
|
|
}
|
|
|
|
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'
|
|
base64config_blobStorage: base64config_blobStorage
|
|
}
|
|
|
|
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: isEmptyStorageAccountName ? storageAccount.name : existingStorageAccount.name
|
|
base64config_blobStorage: base64config_blobStorage
|
|
}
|
|
|
|
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
|
|
|
|
echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage.sh
|
|
chmod +x /usr/local/bin/config_blobStorage.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; }
|
|
|
|
#Config blob storage
|
|
/usr/local/bin/config_blobStorage.sh || { echo "[OpenVidu] error configuring Blob Storage"; 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
|
|
# Creating scale in lock
|
|
set +e
|
|
az storage blob upload --account-name ${storageAccountName} --container-name automation-locks --name lock.txt --file /dev/null --auth-mode key
|
|
set -e
|
|
|
|
#Finish all the nodes
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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: isEmptyStorageAccountName ? storageAccount.name : existingStorageAccount.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=SIGQUIT openvidu || true
|
|
docker container kill --signal=SIGQUIT ingress || true
|
|
docker container kill --signal=SIGQUIT egress || true
|
|
for agent_container in $(docker ps --filter "label=openvidu-agent=true" --format '{{.Names}}'); do
|
|
docker container kill --signal=SIGQUIT "$agent_container"
|
|
done
|
|
|
|
# Wait for running containers to not be openvidu, ingress or egress
|
|
while [ $(docker ps --filter "label=openvidu-agent=true" -q | wc -l) -gt 0 ] || \
|
|
[ $(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 delete_mediaNode_ScriptMediaTemplate = '''
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
az login --identity
|
|
|
|
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 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"; /usr/local/bin/delete_media_node.sh; }
|
|
|
|
# Start OpenVidu
|
|
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; /usr/local/bin/delete_media_node.sh; }
|
|
'''
|
|
|
|
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 delete_mediaNode_ScriptMedia = reduce(
|
|
items(stopMediaNodeParams),
|
|
{ value: delete_mediaNode_ScriptMediaTemplate },
|
|
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
|
|
).value
|
|
|
|
var base64installMedia = base64(installScriptMedia)
|
|
var base64stopMediaNode = base64(stop_media_nodesScriptMedia)
|
|
var base64delete_mediaNode_ScriptMedia = base64(delete_mediaNode_ScriptMedia)
|
|
|
|
var userDataParamsMedia = {
|
|
base64install: base64installMedia
|
|
base64stop: base64stopMediaNode
|
|
base64delete_mediaNode: base64delete_mediaNode_ScriptMedia
|
|
resourceGroupName: resourceGroup().name
|
|
vmScaleSetName: '${stackName}-mediaNodeScaleSet'
|
|
}
|
|
|
|
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: isEmptyStorageAccountName ? storageAccount.name : existingStorageAccount.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
|
|
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 roleAssignmentMasterNode1 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
|
name: guid('roleAssignmentForMasterNode${openviduMasterNode1.name}')
|
|
scope: resourceGroup()
|
|
properties: {
|
|
roleDefinitionId: subscriptionResourceId(
|
|
'Microsoft.Authorization/roleDefinitions',
|
|
'b24988ac-6180-42a0-ab88-20f7382dd24c'
|
|
)
|
|
principalId: openviduMasterNode1.identity.principalId
|
|
}
|
|
}
|
|
|
|
resource roleAssignmentMasterNode2 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
|
name: guid('roleAssignmentForMasterNode${openviduMasterNode2.name}')
|
|
scope: resourceGroup()
|
|
properties: {
|
|
roleDefinitionId: subscriptionResourceId(
|
|
'Microsoft.Authorization/roleDefinitions',
|
|
'b24988ac-6180-42a0-ab88-20f7382dd24c'
|
|
)
|
|
principalId: openviduMasterNode2.identity.principalId
|
|
}
|
|
}
|
|
|
|
resource roleAssignmentMasterNode3 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
|
name: guid('roleAssignmentForMasterNode${openviduMasterNode3.name}')
|
|
scope: resourceGroup()
|
|
properties: {
|
|
roleDefinitionId: subscriptionResourceId(
|
|
'Microsoft.Authorization/roleDefinitions',
|
|
'b24988ac-6180-42a0-ab88-20f7382dd24c'
|
|
)
|
|
principalId: openviduMasterNode3.identity.principalId
|
|
}
|
|
}
|
|
|
|
resource roleAssignmentMasterNode4 '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 = ''
|
|
|
|
var isEmptyAutomationAccountName = automationAccountName == ''
|
|
|
|
module webhookModule '../../shared/webhookdeployment.json' = {
|
|
params: {
|
|
automationAccountName: isEmptyAutomationAccountName
|
|
? uniqueString(resourceGroup().id, openviduMasterNode1.id)
|
|
: 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 = publicIpAddressObject.newOrExistingOrNone == 'none'
|
|
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'
|
|
}
|
|
}
|
|
|
|
var ipExists = publicIpAddressObject.newOrExistingOrNone == 'existing'
|
|
|
|
resource publicIP_LoadBalancer_ifExisting 'Microsoft.Network/publicIPAddresses@2023-11-01' existing = if (ipExists == true) {
|
|
name: publicIpAddressObject.name
|
|
}
|
|
|
|
var ipNew = publicIpAddressObject.newOrExistingOrNone == 'new'
|
|
|
|
resource publicIP_LoadBalancer_ifNew 'Microsoft.Network/publicIPAddresses@2023-11-01' existing = if (ipNew == true) {
|
|
name: publicIpAddressObject.name
|
|
}
|
|
|
|
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
|
|
: ipNew ? publicIP_LoadBalancer_ifNew.id : publicIP_LoadBalancer_ifExisting.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: []
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
dependsOn: [
|
|
subnetMasterNode1
|
|
]
|
|
}
|
|
|
|
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'
|
|
}
|
|
}
|
|
{
|
|
name: 'WebRTC_traffic_TCP'
|
|
properties: {
|
|
protocol: 'Tcp'
|
|
sourceAddressPrefix: '*'
|
|
sourcePortRange: '*'
|
|
destinationAddressPrefix: '*'
|
|
destinationPortRanges: [
|
|
'50000'
|
|
'60000'
|
|
]
|
|
access: 'Allow'
|
|
priority: 150
|
|
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: 160
|
|
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: 170
|
|
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: 180
|
|
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: 190
|
|
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: 200
|
|
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: 210
|
|
direction: 'Inbound'
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------- STORAGE ACCOUNT ----------------------------------------*/
|
|
|
|
@description('Name of an 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.')
|
|
param storageAccountName string = ''
|
|
|
|
var isEmptyStorageAccountName = storageAccountName == ''
|
|
|
|
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = if (isEmptyStorageAccountName == true) {
|
|
name: uniqueString(resourceGroup().id)
|
|
location: resourceGroup().location
|
|
sku: {
|
|
name: 'Standard_LRS'
|
|
}
|
|
kind: 'StorageV2'
|
|
properties: {
|
|
accessTier: 'Cool'
|
|
supportsHttpsTrafficOnly: true
|
|
}
|
|
}
|
|
|
|
resource existingStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (isEmptyStorageAccountName == false) {
|
|
name: storageAccountName
|
|
}
|
|
|
|
resource blobContainerScaleIn 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = if (isEmptyStorageAccountName == true) {
|
|
name: '${storageAccount.name}/default/automation-locks'
|
|
properties: {
|
|
publicAccess: 'None'
|
|
}
|
|
}
|
|
|
|
@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.')
|
|
param appDataContainerName string = ''
|
|
|
|
var isEmptyAppDataContainerName = appDataContainerName == ''
|
|
|
|
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = if (isEmptyStorageAccountName == true) {
|
|
name: isEmptyAppDataContainerName
|
|
? '${storageAccount.name}/default/openvidu-appdata'
|
|
: '${storageAccount.name}/default/${appDataContainerName}'
|
|
properties: {
|
|
publicAccess: 'None'
|
|
}
|
|
}
|
|
|
|
@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.')
|
|
param clusterDataContainerName string = ''
|
|
|
|
var isEmptyClusterContainerName = clusterDataContainerName == ''
|
|
|
|
resource clusterDatablobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = if (isEmptyStorageAccountName == true) {
|
|
name: isEmptyClusterContainerName
|
|
? '${storageAccount.name}/default/openvidu-clusterdata'
|
|
: '${storageAccount.name}/default/${clusterDataContainerName}'
|
|
properties: {
|
|
publicAccess: 'None'
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------- OUTPUTS -------------------------------------------*/
|