* added an enum for the backup behavior

* straightened the backup action selection
This commit is contained in:
2025-03-19 16:49:06 +01:00
parent f478d2adea
commit 4b853a9030

View File

@@ -1,241 +1,269 @@
<#
.SYNOPSIS
Push a superset from prodDB to the BAG Azure managed sql instance
.DESCRIPTION enum backupBehavior{
This function will do those operations: Auto
- Check if the superset given is a snapshot or a database Force
if it's a snapshot, the source database behind the snapshot is backed up Skip
- Authenticate to Azur using a service principal (with a certificate authentication) }
- Create a SAS tocken from Azure Blob Storage
- Refresh credentials on prodDB to access the storage account <#
- Check if a blob of the superset we want to push is more than 1 day old .SYNOPSIS
- if no blob exists, force a backup Push a superset from prodDB to the BAG Azure managed sql instance
- if a blob exists but is aged of less than 1 full day, skip the backup
- if a blob exists but is older than 1 full day, force a new backup .DESCRIPTION
- Refresh the credential with the SAS token on the BAG managed sql instance This function will do those operations:
- Drop the target database if it exists (we cannot restore over an existing db in managed instances) - Check if the superset given is a snapshot or a database
- Restore the backup in the cloud db if it's a snapshot, the source database behind the snapshot is backed up
- Create logins on the restored db for the login [sql-au_bag_apv] - Authenticate to Azur using a service principal (with a certificate authentication)
- Give db_datareader and EXECUTE permission on the restored db to [sql-au_bag_apv] - Create a SAS tocken from Azure Blob Storage
- Refresh credentials on prodDB to access the storage account
.PARAMETERS - Check if a blob of the superset we want to push is more than 1 day old
[string] $supersetToCopy - if no blob exists, force a backup
The name of the superset to transfert. for exemple: product_superset - if a blob exists but is aged of less than 1 full day, skip the backup
- if a blob exists but is older than 1 full day, force a new backup
.EXAMPLES - Refresh the credential with the SAS token on the BAG managed sql instance
push-superset -supersetToCopy Artikel_History_Superset - Drop the target database if it exists (we cannot restore over an existing db in managed instances)
- Restore the backup in the cloud db
#> - Create logins on the restored db for the login [sql-au_bag_apv]
function push-superset([string] $supersetToCopy){ - Give db_datareader and EXECUTE permission on the restored db to [sql-au_bag_apv]
# Variables .PARAMETERS
$tenantId = "7844775a-a9cc-4c33-a5ae-36dcf6660f45" #Galenica [string] $supersetToCopy
$clientId = "d28076dd-2108-4718-802e-cd3c35fd5505" #pcpl-BAGSpezListePrd-DBBackup The name of the superset to transfert. for exemple: product_superset
$skipBackup = "auto" #auto = check age and skip if backup is less than 1 day old, $true to force skip backup, $false to force backup
$backupAutoBehavior
write-info "Starting push of $supersetToCopy to the cloud" auto = check age and skip if backup is less than 1 day old, $true to force backup, $false to skip backup
##do not alter below .EXAMPLES
$serverInstance = "SWMDATASQLPRD01.centralinfra.net" push-superset -supersetToCopy Artikel_History_Superset
$databaseName = $null
$storageAccountName = "stbagspezlisteprdsql" #>
$containerName = "sqlbakfiles" function push-superset{
$resourceGroupName="rg-BAGSpezListePrd-SQL" [CmdletBinding()]
$vaultName="kv-BAGSpezListePrd-bkp" param(
$secretName="superuser" [Parameter(Mandatory=$true)]
$blobPermissions="rwd" [string] $supersetToCopy,
$expiryTime = (Get-Date).AddHours(1) # SAS token valid for 1 hour
$backupFileName = "$supersetToCopy.bak" [Parameter(mandatory=$false)]
[backupBehavior] $backupAutoBehavior = [backupBehavior]::Auto
$mod = Get-Module -Name Az.Accounts )
if($null -eq $mod){
Install-Module -Name Az.KeyVault -Scope CurrentUser # Variables
} $tenantId = "7844775a-a9cc-4c33-a5ae-36dcf6660f45" #Galenica
$clientId = "d28076dd-2108-4718-802e-cd3c35fd5505" #pcpl-BAGSpezListePrd-DBBackup
$mod = Get-Module -Name Az.Storage $skipBackup = $false
if($null -eq $mod){
Install-Module -Name Az.Storage -Scope CurrentUser Write-Information "Starting push of $supersetToCopy to the cloud"
}
##do not alter below
$mod = Get-Module -Name sqlserver $serverInstance = "SWMDATASQLPRD01.centralinfra.net"
if($null -eq $mod){ $databaseName = $null
Install-Module -Name sqlserver -Scope CurrentUser -AllowClobber $storageAccountName = "stbagspezlisteprdsql"
} $containerName = "sqlbakfiles"
$resourceGroupName="rg-BAGSpezListePrd-SQL"
$vaultName="kv-BAGSpezListePrd-bkp"
#Managed instance related $secretName="superuser"
$MILogin='superuser' $blobPermissions="rwd"
$MIPwd=$null #fetched from key vault later $expiryTime = (Get-Date).AddHours(1) # SAS token valid for 1 hour
$MIInstance="sqlmi-bagspezlisteprd-sqlinstance.75ff9425ac13.database.windows.net" $backupFileName = "$supersetToCopy.bak"
#check for the origin of product_superset $mod = Get-Module -Name Az.Accounts
$query=" if($null -eq $mod){
SELECT s.name AS superset, d.name AS srcDb Install-Module -Name Az.KeyVault -Scope CurrentUser
FROM sys.databases s }
JOIN sys.databases d ON d.[database_id] = s.[source_database_id]
WHERE s.name='$supersetToCopy' $mod = Get-Module -Name Az.Storage
" if($null -eq $mod){
$res = Invoke-Sqlcmd -ServerInstance $serverInstance -Query $query Install-Module -Name Az.Storage -Scope CurrentUser
$databaseName = $res.srcDb }
if($null -eq $databaseName){
#superset is not a db snapshot... $mod = Get-Module -Name sqlserver
$databaseName = $supersetToCopy if($null -eq $mod){
} Install-Module -Name sqlserver -Scope CurrentUser -AllowClobber
}
# Log in to Azure
$null = Connect-AzAccount -ServicePrincipal -ApplicationId $clientId -Tenant $tenantId -Subscription BAGSpezListePrd -CertificateThumbprint 7bd45f67999015c7742db25efc86bae97590c57d
#Managed instance related
# Get the storage account context $MILogin='superuser'
$storageAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName $MIPwd=$null #fetched from key vault later
$context = $storageAccount.Context $MIInstance="sqlmi-bagspezlisteprd-sqlinstance.75ff9425ac13.database.windows.net"
# Get the blob properties #check for the origin of product_superset
$backupFile = "https://$storageAccountName.blob.core.windows.net/$containerName/$backupFileName" $query="
if($skipBackup -eq "auto") SELECT s.name AS superset, d.name AS srcDb
{ FROM sys.databases s
try{ JOIN sys.databases d ON d.[database_id] = s.[source_database_id]
$blob = Get-AzStorageBlob -Container $containerName -Blob $backupFileName -Context $context WHERE s.name='$supersetToCopy'
} "
catch{ $res = Invoke-Sqlcmd -ServerInstance $serverInstance -Query $query
$blob = $null $databaseName = $res.srcDb
} if($null -eq $databaseName){
#superset is not a db snapshot...
if($null -eq $blob){ $databaseName = $supersetToCopy
$skipBackup=$false }
Write-Output "Blob does not exists, forcing backup"
} # Log in to Azure
else{ $null = Connect-AzAccount -ServicePrincipal -ApplicationId $clientId -Tenant $tenantId -Subscription BAGSpezListePrd -CertificateThumbprint 7bd45f67999015c7742db25efc86bae97590c57d
# Calculate the age of the blob
$currentDate = Get-Date # Get the storage account context
$blobLastModified = $blob | Select-Object -ExpandProperty LastModified $storageAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName
$blobLastModifiedDateTime = [DateTime]::Parse($blobLastModified.ToString()) $context = $storageAccount.Context
$blobAge = $currentDate - $blobLastModifiedDateTime
# Get the blob properties
if($blobAge.Days -eq 0){ $backupFile = "https://$storageAccountName.blob.core.windows.net/$containerName/$backupFileName"
$skipBackup=$true if($backupAutoBehavior -eq [backupBehavior]::Auto)
Write-Output "Blob exists and is less than a day old, skipping backup" {
} try{
else{ $blob = Get-AzStorageBlob -Container $containerName -Blob $backupFileName -Context $context
$skipBackup=$false }
Write-Output "Blob exists and is older than a day, forcing backup" catch{
} $blob = $null
} }
}
if($null -eq $blob){
# Generate the SAS token $skipBackup=$false
$sasToken = New-AzStorageBlobSASToken -Context $context -Container $containerName -Blob $backupFileName -Permission $blobPermissions -ExpiryTime $expiryTime Write-Output "Blob does not exists, forcing backup"
}
# Save token in db else{
$sqlQuery = " # Calculate the age of the blob
IF NOT EXISTS (SELECT * FROM sys.credentials WHERE name = 'https://$storageAccountName.blob.core.windows.net/$containerName') $currentDate = Get-Date
BEGIN $blobLastModified = $blob | Select-Object -ExpandProperty LastModified
CREATE CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName] $blobLastModifiedDateTime = [DateTime]::Parse($blobLastModified.ToString())
WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken'; $blobAge = $currentDate - $blobLastModifiedDateTime
END
ELSE if($blobAge.Days -eq 0){
BEGIN $skipBackup=$true
ALTER CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName] Write-Output "Blob exists and is less than a day old, skipping backup"
WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken'; }
END else{
" $skipBackup=$false
Invoke-Sqlcmd -ServerInstance $serverInstance -Query $sqlQuery Write-Output "Blob exists and is older than a day, forcing backup"
Write-Output "Credential refreshed on $serverInstance" }
}
#Back Up Database }
$url=$backupFile else{
$sqlQuery = " if($backupAutoBehavior -eq [backupBehavior]::Force){
BACKUP DATABASE [$databaseName] $skipBackup = $false
TO URL = N'$url' }
WITH FORMAT, MEDIANAME = 'SQLServerBackups', NAME = 'Full Backup of $databaseName';
" if($backupAutoBehavior -eq [backupBehavior]::Skip){
if($false -eq $skipBackup){ $skipBackup = $true
Invoke-Sqlcmd -ServerInstance $serverInstance -Query $sqlQuery }
Write-Output "backup done" }
}
else{ # Generate the SAS token
write-output "Backup skipped." $sasToken = New-AzStorageBlobSASToken -Context $context -Container $containerName -Blob $backupFileName -Permission $blobPermissions -ExpiryTime $expiryTime
}
# Save token in db
#fetch the Managed Instance password $sqlQuery = "
$MIPwd = Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -AsPlainText IF NOT EXISTS (SELECT * FROM sys.credentials WHERE name = 'https://$storageAccountName.blob.core.windows.net/$containerName')
BEGIN
#craft credential for MI connection CREATE CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName]
$securePassword = ConvertTo-SecureString $MIPwd -AsPlainText -Force WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken';
$credentialMI = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $MILogin, $securePassword END
ELSE
#add sas token BEGIN
$sqlCred=" ALTER CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName]
IF NOT EXISTS (SELECT * FROM sys.credentials WHERE name = 'https://$storageAccountName.blob.core.windows.net/$containerName') WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken';
BEGIN END
CREATE CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName] "
WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken'; Invoke-Sqlcmd -ServerInstance $serverInstance -Query $sqlQuery
END Write-Output "Credential refreshed on $serverInstance"
ELSE
BEGIN #Back Up Database
ALTER CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName] $url=$backupFile
WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken'; $sqlQuery = "
END BACKUP DATABASE [$databaseName]
" TO URL = N'$url'
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlCred -Credential $credentialMI WITH FORMAT, MEDIANAME = 'SQLServerBackups', NAME = 'Full Backup of $databaseName';
Write-Output "Credential refreshed on $MIInstance" "
if($false -eq $skipBackup){
#drop existing db Invoke-Sqlcmd -ServerInstance $serverInstance -Query $sqlQuery
$sqlDrop=" Write-Output "backup done"
}
IF EXISTS( else{
SELECT 1 write-output "Backup skipped."
FROM sys.databases d }
WHERE d.name ='$supersetToCopy'
) #fetch the Managed Instance password
BEGIN $MIPwd = Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -AsPlainText
DROP DATABASE $supersetToCopy;
END #craft credential for MI connection
" $securePassword = ConvertTo-SecureString $MIPwd -AsPlainText -Force
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlDrop -Credential $credentialMI $credentialMI = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $MILogin, $securePassword
Write-Output "Dropped existing $supersetToCopy db (if needed)"
#add sas token
#restore superset $sqlCred="
$url=$backupFile IF NOT EXISTS (SELECT * FROM sys.credentials WHERE name = 'https://$storageAccountName.blob.core.windows.net/$containerName')
$sqlRestore=" BEGIN
RESTORE DATABASE [$supersetToCopy] FROM URL = N'$url' CREATE CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName]
" WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken';
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlRestore -Credential $credentialMI END
write-output "Restored $supersetToCopy" ELSE
BEGIN
#create user for sql-au_bag_apv ALTER CREDENTIAL [https://$storageAccountName.blob.core.windows.net/$containerName]
$sqlUser=" WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = '$sasToken';
END
IF NOT EXISTS ( "
SELECT * Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlCred -Credential $credentialMI
FROM sys.database_principals s Write-Output "Credential refreshed on $MIInstance"
WHERE s.name='sql-au_bag_apv'
) #drop existing db
BEGIN $sqlDrop="
CREATE USER [sql-au_bag_apv] FOR LOGIN [sql-au_bag_apv];
END IF EXISTS(
" SELECT 1
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlUser -Credential $credentialMI -Database $supersetToCopy FROM sys.databases d
write-output "Created user for login [sql-au_bag_apv] in $supersetToCopy" WHERE d.name ='$supersetToCopy'
)
BEGIN
#give db_datareader DROP DATABASE $supersetToCopy;
$sqlPerms=" END
"
ALTER ROLE [db_datareader] ADD MEMBER [sql-au_bag_apv]; Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlDrop -Credential $credentialMI
GRANT EXECUTE TO [sql-au_bag_apv]; Write-Output "Dropped existing $supersetToCopy db (if needed)"
" #restore superset
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlPerms -Credential $credentialMI -Database $supersetToCopy $url=$backupFile
write-output "Added user [sql-au_bag_apv] with read and execute permissions to $supersetToCopy" $sqlRestore="
RESTORE DATABASE [$supersetToCopy] FROM URL = N'$url'
} "
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlRestore -Credential $credentialMI
<# write-output "Restored $supersetToCopy"
backup product_superset__0 : 00:13:00
restore product_superset : 00:05:40 #create user for sql-au_bag_apv
#> $sqlUser="
#push-superset -supersetToCopy sl2007_superset IF NOT EXISTS (
push-superset -supersetToCopy Artikel_History_Superset SELECT *
#push-superset -supersetToCopy product_superset FROM sys.database_principals s
WHERE s.name='sql-au_bag_apv'
)
BEGIN
CREATE USER [sql-au_bag_apv] FOR LOGIN [sql-au_bag_apv];
END
"
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlUser -Credential $credentialMI -Database $supersetToCopy
write-output "Created user for login [sql-au_bag_apv] in $supersetToCopy"
#give db_datareader
$sqlPerms="
ALTER ROLE [db_datareader] ADD MEMBER [sql-au_bag_apv];
GRANT EXECUTE TO [sql-au_bag_apv];
"
Invoke-Sqlcmd -ServerInstance $MIInstance -Query $sqlPerms -Credential $credentialMI -Database $supersetToCopy
write-output "Added user [sql-au_bag_apv] with read and execute permissions to $supersetToCopy"
}
<#
backup product_superset__0 : 00:13:00
restore product_superset : 00:05:40
#>
#push-superset -supersetToCopy sl2007_superset -backupAutoBehavior Auto
push-superset -supersetToCopy Artikel_History_Superset -backupAutoBehavior Auto
#push-superset -supersetToCopy product_superset -backupAutoBehavior Auto