mirror of https://github.com/OpenVidu/openvidu.git
openvidu-deployment: azure - added existing storage account support in CE, Elastic and HA deployments
parent
ed579b4e72
commit
b8fc003a4c
|
@ -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' = {
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
"metadata": {
|
||||
"_generator": {
|
||||
"name": "bicep",
|
||||
"version": "0.34.44.8038",
|
||||
"templateHash": "6604641218613788020"
|
||||
"version": "0.35.1.17967",
|
||||
"templateHash": "17646090837985029822"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
|
|
|
@ -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
|
@ -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}'
|
||||
|
|
|
@ -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')))]",
|
||||
|
|
Loading…
Reference in New Issue