openvidu-deployment: azure - added existing storage account support in CE, Elastic and HA deployments

master
Piwccle 2025-05-13 11:01:22 +02:00
parent ed579b4e72
commit b8fc003a4c
6 changed files with 131 additions and 51 deletions

View File

@ -728,7 +728,7 @@ var store_secretScript = reduce(
).value
var blobStorageParams = {
storageAccountName: storageAccount.name
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
storageAccountKey: listKeys(storageAccount.id, '2021-04-01').keys[0].value
storageAccountContainerName: isEmptyContainerName ? 'openvidu-appdata' : '${containerName}'
}
@ -1100,6 +1100,11 @@ resource webServerSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-11
/*------------------------------------------- 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 == ''
@description('Name of the bucket where OpenVidu will store the recordings. If not specified, a default bucket will be created.')
param containerName string = ''
@ -1116,6 +1121,10 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
}
}
resource exisitngStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (isEmptyStorageAccountName == false) {
name: storageAccountName
}
var isEmptyContainerName = containerName == ''
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {

View File

@ -4,8 +4,8 @@
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.34.44.8038",
"templateHash": "6604641218613788020"
"version": "0.35.1.17967",
"templateHash": "17646090837985029822"
}
},
"parameters": {

View File

@ -890,7 +890,7 @@ set -e
# Install dir and config dir
INSTALL_DIR="/opt/openvidu"
CONFIG_DIR="${INSTALL_DIR}/config"
CLUSTER_CONFIG_DIR="${INSTALL_DIR}/config/cluster"
az login --identity
@ -899,9 +899,9 @@ 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|" "${CONFIG_DIR}/openvidu.env"
sed -i "s|AZURE_ACCOUNT_KEY=.*|AZURE_ACCOUNT_KEY=$AZURE_ACCOUNT_KEY|" "${CONFIG_DIR}/openvidu.env"
sed -i "s|AZURE_CONTAINER_NAME=.*|AZURE_CONTAINER_NAME=$AZURE_CONTAINER_NAME|" "${CONFIG_DIR}/openvidu.env"
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 installScriptMaster = reduce(
@ -935,7 +935,7 @@ var store_secretScriptMaster = reduce(
).value
var blobStorageParams = {
storageAccountName: storageAccount.name
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
storageAccountKey: listKeys(storageAccount.id, '2021-04-01').keys[0].value
storageAccountContainerName: isEmptyContainerName ? 'openvidu-appdata' : '${containerName}'
}
@ -967,7 +967,7 @@ var userDataParamsMasterNode = {
base64restart: base64restartMaster
base64config_blobStorage: base64config_blobStorage
keyVaultName: keyVaultName
storageAccountName: storageAccount.name
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
}
var userDataTemplateMasterNode = '''
@ -1168,7 +1168,7 @@ var stopMediaNodeParams = {
subscriptionId: subscription().subscriptionId
resourceGroupName: resourceGroup().name
vmScaleSetName: '${stackName}-mediaNodeScaleSet'
storageAccountName: storageAccount.name
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
}
var stop_media_nodesScriptMediaTemplate = '''
@ -1286,7 +1286,7 @@ resource openviduScaleSetMediaNode 'Microsoft.Compute/virtualMachineScaleSets@20
location: location
tags: {
InstanceDeleteTime: datetime
storageAccount: storageAccount.name
storageAccount: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
}
identity: { type: 'SystemAssigned' }
sku: {
@ -2028,7 +2028,12 @@ resource masterToMediaHttpWhipIngress 'Microsoft.Network/networkSecurityGroups/s
/*------------------------------------------- STORAGE ACCOUNT ----------------------------------------*/
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
@description('Name of the existing storage account. It is essential that this parameter is filled just when you want to save recordings and still using the same container after an update. If not specified, a new storage account will be generated.')
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: {
@ -2041,7 +2046,11 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
}
}
resource blobContainerScaleIn 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
resource exisitngStorageAccount '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'
@ -2053,7 +2062,7 @@ param containerName string = ''
var isEmptyContainerName = containerName == ''
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = if (isEmptyStorageAccountName == true) {
name: isEmptyContainerName
? '${storageAccount.name}/default/openvidu-appdata'
: '${storageAccount.name}/default/${containerName}'

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ and an Elastic IP, you can use this option to generate a Let's Encrypt certifica
])
param certificateType string = 'selfsigned'
@description('Domain name for the OpenVidu Deployment. Blank will generate default domain')
@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')
@ -986,6 +986,26 @@ systemctl stop openvidu
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 },
@ -1034,6 +1054,18 @@ var store_secretScriptMaster = reduce(
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var blobStorageParams = {
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
storageAccountKey: listKeys(storageAccount.id, '2021-04-01').keys[0].value
storageAccountContainerName: isEmptyContainerName ? 'openvidu-appdata' : '${containerName}'
}
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)
@ -1045,6 +1077,7 @@ 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
@ -1096,7 +1129,8 @@ var userDataParamsMasterNode4 = {
base64restart: base64restartMaster
keyVaultName: keyVaultName
masterNodeNum: '4'
storageAccountName: storageAccount.name
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
base64config_blobStorage: base64config_blobStorage
}
var userDataTemplateMasterNode = '''
@ -1159,9 +1193,17 @@ echo "@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log" 2>&1 |
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
# Configuring blob storage
echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage.sh
chmod +x /usr/local/bin/config_blobStorage.sh
/usr/local/bin/config_blobStorage.sh || { echo "[OpenVidu] error configuring Blob Storage"; exit 1; }
#Finish all the nodes
az keyvault secret set --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --value "true"
fi
@ -1426,7 +1468,7 @@ var stopMediaNodeParams = {
subscriptionId: subscription().subscriptionId
resourceGroupName: resourceGroup().name
vmScaleSetName: '${stackName}-mediaNodeScaleSet'
storageAccountName: storageAccount.name
storageAccountName: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
}
var stop_media_nodesScriptMediaTemplate = '''
@ -1524,6 +1566,8 @@ var base64stopMediaNode = base64(stop_media_nodesScriptMedia)
var userDataParamsMedia = {
base64install: base64installMedia
base64stop: base64stopMediaNode
resourceGroupName: resourceGroup().name
vmScaleSetName: '${stackName}-mediaNodeScaleSet'
}
var userDataMediaNode = reduce(
@ -1540,7 +1584,7 @@ resource openviduScaleSetMediaNode 'Microsoft.Compute/virtualMachineScaleSets@20
location: location
tags: {
InstanceDeleteTime: datetime
storageAccount: storageAccount.name
storageAccount: isEmptyStorageAccountName ? storageAccount.name : exisitngStorageAccount.name
}
identity: { type: 'SystemAssigned' }
sku: {
@ -2922,7 +2966,12 @@ resource masterToMediaClientIngress 'Microsoft.Network/networkSecurityGroups/sec
/*------------------------------------------- STORAGE ACCOUNT ----------------------------------------*/
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
@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: {
@ -2935,19 +2984,23 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
}
}
resource blobContainerScaleIn 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
resource exisitngStorageAccount '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 not specified, a default bucket will be created.')
@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.')
param containerName string = ''
var isEmptyContainerName = containerName == ''
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = if (isEmptyStorageAccountName == true) {
name: isEmptyContainerName
? '${storageAccount.name}/default/openvidu-appdata'
: '${storageAccount.name}/default/${containerName}'

View File

@ -4,8 +4,8 @@
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.34.44.8038",
"templateHash": "5609072357229822186"
"version": "0.35.1.17967",
"templateHash": "4378002790668359491"
}
},
"parameters": {
@ -30,7 +30,7 @@
"domainName": {
"type": "string",
"metadata": {
"description": "Domain name for the OpenVidu Deployment. Blank will generate default domain"
"description": "Domain name for the OpenVidu Deployment."
}
},
"ownPublicCertificate": {
@ -395,11 +395,18 @@
"description": "Automation Account Name to create a runbook inside it for scale in"
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "",
"metadata": {
"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."
}
},
"containerName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Name of the bucket where OpenVidu will store the recordings. If not specified, a default bucket will be created."
"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."
}
}
},
@ -520,6 +527,7 @@
"store_secretScriptTemplateMaster": "#!/bin/bash\nset -e\n\naz login --identity --allow-no-subscriptions > /dev/null\n\n# Modes: save, generate\n# save mode: save the secret in the secret manager\n# generate mode: generate a random password and save it in the secret manager\nMODE=\"$1\"\n\nif [[ \"$MODE\" == \"generate\" ]]; then\n SECRET_KEY_NAME=\"$2\"\n PREFIX=\"${3:-}\"\n LENGTH=\"${4:-44}\"\n RANDOM_PASSWORD=\"$(openssl rand -base64 64 | tr -d '+/=\\n' | cut -c -${LENGTH})\"\n RANDOM_PASSWORD=\"${PREFIX}${RANDOM_PASSWORD}\"\n az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $RANDOM_PASSWORD > /dev/null\n if [[ $? -ne 0 ]]; then\n echo \"Error generating secret\"\n fi\n echo \"$RANDOM_PASSWORD\"\nelif [[ \"$MODE\" == \"save\" ]]; then\n SECRET_KEY_NAME=\"$2\"\n SECRET_VALUE=\"$3\"\n az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $SECRET_VALUE > /dev/null\n if [[ $? -ne 0 ]]; then\n echo \"Error generating secret\"\n fi\n echo \"$SECRET_VALUE\"\nelse\n exit 1\nfi\n",
"check_app_readyScriptMaster": "#!/bin/bash\nset -e\nwhile true; do\n HTTP_STATUS=$(curl -Ik http://localhost:7880/twirp/health | head -n1 | awk '{print $2}')\n if [ $HTTP_STATUS == 200 ]; then\n break\n fi\n sleep 5\ndone\n",
"restartScriptMaster": "#!/bin/bash\nset -e\n# Stop all services\nsystemctl stop openvidu\n\n# Update config from secret\n/usr/local/bin/update_config_from_secret.sh\n\n# Start all services\nsystemctl start openvidu\n",
"config_blobStorageTemplate": "#!/bin/bash\nset -e\n\n# Install dir and config dir\nINSTALL_DIR=\"/opt/openvidu\"\nCLUSTER_CONFIG_DIR=\"${INSTALL_DIR}/config/cluster\"\n\naz login --identity\n\n# Config azure blob storage\nAZURE_ACCOUNT_NAME=\"${storageAccountName}\"\nAZURE_ACCOUNT_KEY=$(az storage account keys list --account-name ${storageAccountName} --query '[0].value' -o tsv)\nAZURE_CONTAINER_NAME=\"${storageAccountContainerName}\"\n\nsed -i \"s|AZURE_ACCOUNT_NAME=.*|AZURE_ACCOUNT_NAME=$AZURE_ACCOUNT_NAME|\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nsed -i \"s|AZURE_ACCOUNT_KEY=.*|AZURE_ACCOUNT_KEY=$AZURE_ACCOUNT_KEY|\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\nsed -i \"s|AZURE_CONTAINER_NAME=.*|AZURE_CONTAINER_NAME=$AZURE_CONTAINER_NAME|\" \"${CLUSTER_CONFIG_DIR}/openvidu.env\"\n",
"installScriptMaster1": "[reduce(items(variables('stringInterpolationParamsMaster1')), createObject('value', variables('installScriptTemplateMaster')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]",
"installScriptMaster2": "[reduce(items(variables('stringInterpolationParamsMaster2')), createObject('value', variables('installScriptTemplateMaster')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]",
"installScriptMaster3": "[reduce(items(variables('stringInterpolationParamsMaster3')), createObject('value', variables('installScriptTemplateMaster')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]",
@ -575,30 +583,16 @@
"keyVaultName": "[variables('keyVaultName')]",
"masterNodeNum": "3"
},
"userDataParamsMasterNode4": {
"base64install": "[variables('base64installMaster4')]",
"base64after_install": "[variables('base64after_installMaster')]",
"base64update_config_from_secret": "[variables('base64update_config_from_secretMaster')]",
"base64update_secret_from_config": "[variables('base64update_secret_from_configMaster')]",
"base64get_value_from_config": "[variables('base64get_value_from_configMaster')]",
"base64store_secret": "[variables('base64store_secretMaster')]",
"base64check_app_ready": "[variables('base64check_app_readyMaster')]",
"base64restart": "[variables('base64restartMaster')]",
"keyVaultName": "[variables('keyVaultName')]",
"masterNodeNum": "4",
"storageAccountName": "[uniqueString(resourceGroup().id)]"
},
"userDataTemplateMasterNode": "#!/bin/bash -x\nset -eu -o pipefail\n\n# Introduce the scripts in the instance\n# install.sh\necho ${base64install} | base64 -d > /usr/local/bin/install.sh\nchmod +x /usr/local/bin/install.sh\n\n# after_install.sh\necho ${base64after_install} | base64 -d > /usr/local/bin/after_install.sh\nchmod +x /usr/local/bin/after_install.sh\n\n# update_config_from_secret.sh\necho ${base64update_config_from_secret} | base64 -d > /usr/local/bin/update_config_from_secret.sh\nchmod +x /usr/local/bin/update_config_from_secret.sh\n\n# update_secret_from_config.sh\necho ${base64update_secret_from_config} | base64 -d > /usr/local/bin/update_secret_from_config.sh\nchmod +x /usr/local/bin/update_secret_from_config.sh\n\n# get_value_from_config.sh\necho ${base64get_value_from_config} | base64 -d > /usr/local/bin/get_value_from_config.sh\nchmod +x /usr/local/bin/get_value_from_config.sh\n\n# store_secret.sh\necho ${base64store_secret} | base64 -d > /usr/local/bin/store_secret.sh\nchmod +x /usr/local/bin/store_secret.sh\n\n# check_app_ready.sh\necho ${base64check_app_ready} | base64 -d > /usr/local/bin/check_app_ready.sh\nchmod +x /usr/local/bin/check_app_ready.sh\n\n# restart.sh\necho ${base64restart} | base64 -d > /usr/local/bin/restart.sh\nchmod +x /usr/local/bin/restart.sh\n\n# Install azure cli\ncurl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash\n\naz login --identity --allow-no-subscriptions\n\napt-get update && apt-get install -y\n\nexport HOME=\"/root\"\n\n# Install OpenVidu\n/usr/local/bin/install.sh || { echo \"[OpenVidu] error installing OpenVidu\"; exit 1; }\n\n# Start OpenVidu\nsystemctl start openvidu || { echo \"[OpenVidu] error starting OpenVidu\"; exit 1; }\n\n# Update shared secret\n/usr/local/bin/after_install.sh || { echo \"[OpenVidu] error updating shared secret\"; exit 1; }\n\n# Launch on reboot\necho \"@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log\" 2>&1 | crontab\n\nMASTER_NODE_NUM=${masterNodeNum}\nif [[ $MASTER_NODE_NUM -eq 4 ]]; then\n set +e\n az storage blob upload --account-name ${storageAccountName} --container-name automation-locks --name lock.txt --file /dev/null --auth-mode key\n set -e\n az keyvault secret set --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --value \"true\"\nfi\n\n# Wait for the app\nsleep 150\n/usr/local/bin/check_app_ready.sh\n",
"userDataTemplateMasterNode": "#!/bin/bash -x\nset -eu -o pipefail\n\n# Introduce the scripts in the instance\n# install.sh\necho ${base64install} | base64 -d > /usr/local/bin/install.sh\nchmod +x /usr/local/bin/install.sh\n\n# after_install.sh\necho ${base64after_install} | base64 -d > /usr/local/bin/after_install.sh\nchmod +x /usr/local/bin/after_install.sh\n\n# update_config_from_secret.sh\necho ${base64update_config_from_secret} | base64 -d > /usr/local/bin/update_config_from_secret.sh\nchmod +x /usr/local/bin/update_config_from_secret.sh\n\n# update_secret_from_config.sh\necho ${base64update_secret_from_config} | base64 -d > /usr/local/bin/update_secret_from_config.sh\nchmod +x /usr/local/bin/update_secret_from_config.sh\n\n# get_value_from_config.sh\necho ${base64get_value_from_config} | base64 -d > /usr/local/bin/get_value_from_config.sh\nchmod +x /usr/local/bin/get_value_from_config.sh\n\n# store_secret.sh\necho ${base64store_secret} | base64 -d > /usr/local/bin/store_secret.sh\nchmod +x /usr/local/bin/store_secret.sh\n\n# check_app_ready.sh\necho ${base64check_app_ready} | base64 -d > /usr/local/bin/check_app_ready.sh\nchmod +x /usr/local/bin/check_app_ready.sh\n\n# restart.sh\necho ${base64restart} | base64 -d > /usr/local/bin/restart.sh\nchmod +x /usr/local/bin/restart.sh\n\n# Install azure cli\ncurl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash\n\naz login --identity --allow-no-subscriptions\n\napt-get update && apt-get install -y\n\nexport HOME=\"/root\"\n\n# Install OpenVidu\n/usr/local/bin/install.sh || { echo \"[OpenVidu] error installing OpenVidu\"; exit 1; }\n\n# Start OpenVidu\nsystemctl start openvidu || { echo \"[OpenVidu] error starting OpenVidu\"; exit 1; }\n\n# Update shared secret\n/usr/local/bin/after_install.sh || { echo \"[OpenVidu] error updating shared secret\"; exit 1; }\n\n# Launch on reboot\necho \"@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log\" 2>&1 | crontab\n\nMASTER_NODE_NUM=${masterNodeNum}\nif [[ $MASTER_NODE_NUM -eq 4 ]]; then\n # Creating scale in lock\n set +e\n az storage blob upload --account-name ${storageAccountName} --container-name automation-locks --name lock.txt --file /dev/null --auth-mode key\n set -e\n \n # Configuring blob storage\n echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage.sh\n chmod +x /usr/local/bin/config_blobStorage.sh\n /usr/local/bin/config_blobStorage.sh || { echo \"[OpenVidu] error configuring Blob Storage\"; exit 1; }\n\n #Finish all the nodes\n az keyvault secret set --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --value \"true\"\nfi\n\n# Wait for the app\nsleep 150\n/usr/local/bin/check_app_ready.sh\n",
"userDataMasterNode1": "[reduce(items(variables('userDataParamsMasterNode1')), createObject('value', variables('userDataTemplateMasterNode')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]",
"userDataMasterNode2": "[reduce(items(variables('userDataParamsMasterNode2')), createObject('value', variables('userDataTemplateMasterNode')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]",
"userDataMasterNode3": "[reduce(items(variables('userDataParamsMasterNode3')), createObject('value', variables('userDataTemplateMasterNode')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]",
"userDataMasterNode4": "[reduce(items(variables('userDataParamsMasterNode4')), createObject('value', variables('userDataTemplateMasterNode')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value]",
"installScriptTemplateMedia": "#!/bin/bash -x\nDOMAIN=\n\n# Install dependencies\napt-get update && apt-get install -y \\\n curl \\\n unzip \\\n jq \\\n wget\n\n# Get own private IP\nPRIVATE_IP=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text\")\n\nWAIT_INTERVAL=1\nMAX_WAIT=10000\nELAPSED_TIME=0\nset +e\nwhile true; do\n # get secret value\n FINISH_MASTER_NODE=$(az keyvault secret show --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --query value -o tsv)\n\n # Check if all master nodes finished\n if [ \"$FINISH_MASTER_NODE\" == \"true\" ]; then\n break\n fi\n\n ELAPSED_TIME=$((ELAPSED_TIME + WAIT_INTERVAL))\n\n # Check if the maximum waiting time has been reached\n if [ $ELAPSED_TIME -ge $MAX_WAIT ]; then\n exit 1\n fi\n\n sleep $WAIT_INTERVAL\ndone\nset -e\n\nMASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_PRIVATE_IP_LIST=\"$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP\"\nREDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)\nENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)\nOPENVIDU_VERSION=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)\n\n# Base command\nINSTALL_COMMAND=\"sh <(curl -fsSL http://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_media_node.sh)\"\n\n# Common arguments\nCOMMON_ARGS=(\n\"--no-tty\"\n\"--install\"\n\"--environment=azure\"\n\"--deployment-type='ha'\"\n\"--node-role='media-node'\"\n\"--master-node-private-ip-list=$MASTER_NODE_PRIVATE_IP_LIST\"\n\"--private-ip=$PRIVATE_IP\"\n\"--enabled-modules='$ENABLED_MODULES'\"\n\"--redis-password=$REDIS_PASSWORD\"\n)\n\n# Construct the final command with all arguments\nFINAL_COMMAND=\"$INSTALL_COMMAND $(printf \"%s \" \"${COMMON_ARGS[@]}\")\"\n\n# Install OpenVidu\nexec bash -c \"$FINAL_COMMAND\"\n",
"stopMediaNodeParams": {
"subscriptionId": "[subscription().subscriptionId]",
"resourceGroupName": "[resourceGroup().name]",
"vmScaleSetName": "[format('{0}-mediaNodeScaleSet', parameters('stackName'))]",
"storageAccountName": "[uniqueString(resourceGroup().id)]"
"storageAccountName": "[if(variables('isEmptyStorageAccountName'), uniqueString(resourceGroup().id), uniqueString(resourceGroup().id))]"
},
"stop_media_nodesScriptMediaTemplate": "#!/bin/bash\nset -e\n\nif ! (set -o noclobber ; echo > /tmp/global.lock) ; then\n exit 1 # the global.lock already exists\nfi\n\n# Execute if docker is installed\nif [ -x \"$(command -v docker)\" ]; then\n\n echo \"Stopping media node services and waiting for termination...\"\n docker container kill --signal=SIGINT openvidu || true\n docker container kill --signal=SIGINT ingress || true\n docker container kill --signal=SIGINT egress || true\n\n # Wait for running containers to not be openvidu, ingress or egress\n while [ $(docker inspect -f '{{.State.Running}}' openvidu 2>/dev/null) == \"true\" ] || \\\n [ $(docker inspect -f '{{.State.Running}}' ingress 2>/dev/null) == \"true\" ] || \\\n [ $(docker inspect -f '{{.State.Running}}' egress 2>/dev/null) == \"true\" ]; do\n echo \"Waiting for containers to stop...\"\n sleep 5\n done\nfi\n\naz login --identity\n\nRESOURCE_GROUP_NAME=${resourceGroupName}\nVM_SCALE_SET_NAME=${vmScaleSetName}\nSUBSCRIPTION_ID=${subscriptionId}\nBEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\" | jq -r '.compute.resourceId')\nINSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')\nRESOURCE_ID=/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Compute/virtualMachineScaleSets/$VM_SCALE_SET_NAME\n\nTIMESTAMP=$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")\naz tag update --resource-id $RESOURCE_ID --operation replace --tags \"STATUS\"=\"HEALTHY\" \"InstanceDeleteTime\"=\"$TIMESTAMP\" \"storageAccount\"=\"${storageAccountName}\"\n\naz vmss delete-instances --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-ids $INSTANCE_ID\n",
"userDataMediaNodeTemplate": "#!/bin/bash -x\nset -eu -o pipefail\n\n# Introduce the scripts in the instance\n# install.sh\necho ${base64install} | base64 -d > /usr/local/bin/install.sh\nchmod +x /usr/local/bin/install.sh\n\n# stop_media_nodes.sh\necho ${base64stop} | base64 -d > /usr/local/bin/stop_media_node.sh\nchmod +x /usr/local/bin/stop_media_node.sh\n\napt-get update && apt-get install -y \napt-get install -y jq\n\n# Install azure cli\ncurl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash\n\naz login --identity\n\n# Protect from scale in actions\nRESOURCE_GROUP_NAME=${resourceGroupName}\nVM_SCALE_SET_NAME=${vmScaleSetName}\nBEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\" | jq -r '.compute.resourceId')\nINSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')\naz vmss update --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-id $INSTANCE_ID --protect-from-scale-in true\n\nexport HOME=\"/root\"\n\n# Install OpenVidu\n/usr/local/bin/install.sh || { echo \"[OpenVidu] error installing OpenVidu\"; exit 1; }\n\n# Start OpenVidu\nsystemctl start openvidu || { echo \"[OpenVidu] error starting OpenVidu\"; exit 1; }\n",
@ -618,6 +612,7 @@
"subnetAddressPrefixMedia": "10.0.0.0/24",
"vNetName": "[format('{0}-virtualNetwork', parameters('stackName'))]"
},
"isEmptyStorageAccountName": "[equals(parameters('storageAccountName'), '')]",
"isEmptyContainerName": "[equals(parameters('containerName'), '')]"
},
"resources": [
@ -879,7 +874,7 @@
"adminPassword": "[parameters('adminSshKey')]",
"linuxConfiguration": "[variables('masterNodeVMSettings').linuxConfiguration]"
},
"userData": "[base64(variables('userDataMasterNode4'))]"
"userData": "[base64(reduce(items(createObject('base64install', variables('base64installMaster4'), 'base64after_install', variables('base64after_installMaster'), 'base64update_config_from_secret', variables('base64update_config_from_secretMaster'), 'base64update_secret_from_config', variables('base64update_secret_from_configMaster'), 'base64get_value_from_config', variables('base64get_value_from_configMaster'), 'base64store_secret', variables('base64store_secretMaster'), 'base64check_app_ready', variables('base64check_app_readyMaster'), 'base64restart', variables('base64restartMaster'), 'keyVaultName', variables('keyVaultName'), 'masterNodeNum', '4', 'storageAccountName', if(variables('isEmptyStorageAccountName'), uniqueString(resourceGroup().id), uniqueString(resourceGroup().id)), 'base64config_blobStorage', base64(reduce(items(createObject('storageAccountName', if(variables('isEmptyStorageAccountName'), uniqueString(resourceGroup().id), uniqueString(resourceGroup().id)), 'storageAccountKey', listKeys(resourceId('Microsoft.Storage/storageAccounts', uniqueString(resourceGroup().id)), '2021-04-01').keys[0].value, 'storageAccountContainerName', if(variables('isEmptyContainerName'), 'openvidu-appdata', format('{0}', parameters('containerName'))))), createObject('value', variables('config_blobStorageTemplate')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value))), createObject('value', variables('userDataTemplateMasterNode')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value)]"
},
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface4', parameters('stackName')))]",
@ -894,7 +889,7 @@
"location": "[variables('location')]",
"tags": {
"InstanceDeleteTime": "[parameters('datetime')]",
"storageAccount": "[uniqueString(resourceGroup().id)]"
"storageAccount": "[if(variables('isEmptyStorageAccountName'), uniqueString(resourceGroup().id), uniqueString(resourceGroup().id))]"
},
"identity": {
"type": "SystemAssigned"
@ -962,7 +957,7 @@
}
]
},
"userData": "[base64(reduce(items(createObject('base64install', base64(reduce(items(createObject('privateIPMasterNode1', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface1', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'privateIPMasterNode2', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface2', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'privateIPMasterNode3', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface3', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'privateIPMasterNode4', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface4', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'keyVaultName', variables('keyVaultName'))), createObject('value', variables('installScriptTemplateMedia')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value), 'base64stop', variables('base64stopMediaNode'))), createObject('value', variables('userDataMediaNodeTemplate')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value)]"
"userData": "[base64(reduce(items(createObject('base64install', base64(reduce(items(createObject('privateIPMasterNode1', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface1', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'privateIPMasterNode2', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface2', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'privateIPMasterNode3', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface3', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'privateIPMasterNode4', reference(resourceId('Microsoft.Network/networkInterfaces', format('{0}-masterNodeNetInterface4', parameters('stackName'))), '2023-11-01').ipConfigurations[0].properties.privateIPAddress, 'keyVaultName', variables('keyVaultName'))), createObject('value', variables('installScriptTemplateMedia')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value), 'base64stop', variables('base64stopMediaNode'), 'resourceGroupName', resourceGroup().name, 'vmScaleSetName', format('{0}-mediaNodeScaleSet', parameters('stackName')))), createObject('value', variables('userDataMediaNodeTemplate')), lambda('curr', 'next', createObject('value', replace(lambdaVariables('curr').value, format('${{{0}}}', lambdaVariables('next').key), lambdaVariables('next').value)))).value)]"
}
},
"dependsOn": [
@ -2433,6 +2428,7 @@
]
},
{
"condition": "[equals(variables('isEmptyStorageAccountName'), true())]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"name": "[uniqueString(resourceGroup().id)]",
@ -2447,6 +2443,7 @@
}
},
{
"condition": "[equals(variables('isEmptyStorageAccountName'), true())]",
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2023-01-01",
"name": "[format('{0}/default/automation-locks', uniqueString(resourceGroup().id))]",
@ -2458,6 +2455,7 @@
]
},
{
"condition": "[equals(variables('isEmptyStorageAccountName'), true())]",
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2023-01-01",
"name": "[if(variables('isEmptyContainerName'), format('{0}/default/openvidu-appdata', uniqueString(resourceGroup().id)), format('{0}/default/{1}', uniqueString(resourceGroup().id), parameters('containerName')))]",