Backing up SVN to Azure Storage
Until such time as I finally get round to the item on my TO DO list that's all about replacing my on-prem SVN server with Visual Studio Online, it would probably be sensible to have backups. Because I've always had multiple copies of what's in the sole repository on the server, I've been a bit lazy about instituting a backup regime for this particular server. The fact that I took the time to craft a backup solution for the SQL Server behind this website (see link above) reminded me that I probably had my priorities slightly skewed. Much though I've invested time and effort into the content on this website, that's disposable when compared to the code that I've written - often for others! So, without any more waffle from me, here's the script that I'm using to backup my SVN repository to Azure, along with the rationale behind some of the odder looking bits of it.
The script for backing up SVN to Azure
The first thing to be aware of is that the svnadmin tool has an explicit command for taking a backup of a repository, that being dump. Theoretically, if there is nothing connected to a repository and no services running to allow connections, you could take a copy of the file-system location for the repository - but why on earth would you try and do that when there's a supported command for the process? It's true that backups taken via svnadmin dump tend to be significantly larger than the "on disk" representation, but that's not a good reason to circumvent a baked-in backup tool. Instead, how about compressing the output to reclaim some of the space? Anyway, on with the script!
Add-Type -Assembly "System.IO.Compression"; Add-Type -Assembly "System.IO.Compression.FileSystem"; $storageAccount = "STORAGE_ACCOUNT_NAME"; $storageKey = "STORAGE_ACCOUNT_KEY"; $storageContainer = "STORAGE_ACCOUNT_TARGET_CONTAINER"; $backupWorkingFolder = "C:\BackupWorkingFolder"; $repositoryRoot = "C:\Repositories"; $repositoryName = "RewardYourTeam"; <# Construct a "unique enough" filename for the backup, composed of the name of the repository being backed up and the current date/time down to second precision #> $backupFileName = "$($repositoryName)_$(Get-Date -Format "yyyyMMddHHmmss").bak"; $backupFileNameAndPath = "$backupWorkingFolder\$backupFileName"; <# Backup the repository, put the backup file into the location specified #> $backupCommandLine = "C:\Program Files\VisualSVN Server\bin\SVNADMIN.exe"; $backupCommandLineParameters = 'dump', "$repositoryRoot\$repositoryName" cmd.exe /c $backupCommandLine $backupCommandLineParameters `> $backupFileNameAndPath $zipFile = [System.IO.Compression.ZipFile]::Open("$backupFileNameAndPath.zip", [System.IO.Compression.ZipArchiveMode]::Create) [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipFile, $backupFileNameAndPath, $backupFileName); $zipFile.Dispose(); <# Authenticate against Azure storage and then write the file to it#> $storageContext = New-AzureStorageContext -StorageAccountName $storageAccount -StorageAccountKey $storageKey Set-AzureStorageBlobContent -Container $storageContainer -Blob "$backupFileName.zip" -File "$backupFileNameAndPath.zip" -Context $storageContext -Force <# Delete the backup file #> Remove-Item -Path $backupFileNameAndPath Remove-Item -Path "$backupFileNameAndPath.zip"
So, why am I breaking out to CMD when it comes to running the meat of this, which is the svnadmin dump command? Well, it turns out that the output from svnadmin dump gets mangled by the PowerShell pipeline (1, 2) and the easiest way to resolve this is to just break-out cmd. There might be a more elegant solution, in fact Visual SVN (the solution I use) comes with a PowerShell module, so chances are there's something there that'll do the job. As a solution that works more universally, working with the svnadmin tool, via cmd.exe trumps it.
The only other oddities/curios within this particular script are:
- `> - to stop PowerShell from stropping over the > symbol, backtick escape it
- CreateEntryFromFile - this is (the clue is probably in the name of the class that contains the method) actually an extension method on the ZipFile class, however, for the purposes of invoking via PowerSg