Octopus includes a migration API that provides the ability to back-up and restore parts of an Octopus Deploy instance remotely.
The API currently includes support for both the partial-export and import commands. The API uses the same Migrator.exe command line tool that you’d typically use to migrate data manually, but the API gives you some additional parameters to orchestrate the process between remote servers.
Note: the migration API is not supported for migrations from self-hosted Octopus Server to Octopus Cloud currently - please see migrating from self-hosted to Octopus Cloud for information on how to migrate to Octopus Cloud.
How it works
When you trigger a migration via the API, your Octopus Server will queue up a migration task that you can view from your Tasks screen. During execution of this task, your Octopus Server will go into maintenance mode to try and minimize any data mutations during the migration. When the task is completed, it will be taken out of maintenance mode.
We advise that you only use the migration API under the same conditions that you’d typically do a manual migration, i.e., during a maintenance period when you know that:
- You’re not going to interrupt your daily deployment operations.
- You’ll minimize the chance of data mutations during the migration itself.
- The versions of your source and destination servers are the same (don’t try and export/import between different versions of Octopus).
The typical process for migrating projects between a source and destination server is as follows:
- Create an API key for your source server (the server you’re exporting from).
- Create an API key for your destination server (the server you’re importing to).
- Get a list of project names that you wish to export from your source server.
- Call the
partial-export
migration API against your source server, telling it the destination server URL, API key, password for your migration package, and the list of project names you want to export (You’ll receive a 200 response from the API telling you the TaskId that has been queued to do the actual work). - At this point, your source server’s task queue will then execute the
partial-export
command usingMigrator.exe
, package up the contents of your export and push it to your destination server’s package feed. - Watch your source server’s migration task in the Octopus UI to know when this operation is complete … Or if you’re really keen, you could write a script that queries the task API and it will let you know when the migration task is complete (as seen in the Octopus.Clients example below).
- Call the
import
migration API against your destination server, telling it the package and password to import from (You’ll receive a 200 response from the API telling you the TaskId that has been queued to do the actual work). - Your destination server’s task queue will then execute an
import
command usingMigrator.exe
. - At this point, your destination server’s task queue will then execute the
import
command usingMigrator.exe
.
Partial export API
Using the partial-export API, we can export one or more of our projects and choose to send the package to the destination Octopus Server’s package feed.
Partial Export API parameters:
Parameter | Description |
---|---|
Password=VALUE | Password to encrypt both the migration package and any sensitive values (This is the shared key between partial-export and import migrations) |
Projects=VALUE | Projects to include in the migration |
PackageId=VALUE | [Optional] Package Name/ID for your export (Defaults to Octopus.Space.Migration if not provided) |
PackageVersion=VALUE | [Optional] SemVer package version for your export (Defaults to 1.0.0-{RandomStringGenerator.Generate(8)} if not provided) |
IgnoreCertificates | [Optional] Excludes certificates from partial export |
IgnoreMachines | [Optional] Excludes machines from partial export |
IgnoreDeployments | [Optional] Excludes deployments from partial export |
IgnoreTenants | [Optional] Excludes tenants from partial export |
IncludeTaskLogs | [Optional] Include the task log folder as part of the export |
EncryptPackage | [Optional] Encrypt the contents of your migration package (Uses the Password as a shared key so this can be decrypted by your destination server) |
DestinationApiKey=VALUE | [Optional] The API key of your destination server (Where you’ll be importing this exported package) |
DestinationPackageFeed=VALUE | [Optional] The destination Octopus Server base URL (e.g. https://your-octopus-url) |
SuccessCallbackUri=VALUE | [Optional] A webhook URL you can add if you wish to be notified on successful completion of the migration task (Your Octopus Server will call this URL using a GET request, appending the packageId and packageVersion to the URL as querystring parameters) |
FailureCallbackUri=VALUE | [Optional] A webhook URL you can add if you wish to be notified on failure of the migration task (Your Octopus Server will call this URL using a GET request) |
TaskId | [Response only] This will be populated with the TaskId that gets queued for this migration |
Import API
The import API lets you import a migration package from your Octopus Server’s built-in package feed (which is where packages are pushed to when using the partial-export API).
Import API parameters:
Parameter | Description |
---|---|
Password=VALUE | Password that was used during the export migration (This is the shared key between partial-export and import migrations) |
PackageId=VALUE | Package Name/ID that we are importing |
PackageVersion=VALUE | SemVer package version that we are importing |
DestinationPackageFeedSpaceId=VALUE | [Optional] If using the Spaces feature, the ID of the Space where the package containing the data to migrate will be uploaded. This is only for the package; the data in the package specifies its own destination Space. |
IsEncryptedPackage | [Optional] Tells us whether the package was encrypted (E.g. if you set EncryptPackage on export, you need to set this to True ) |
IsDryRun | [Optional] Do not commit changes, just print what would have happened (This allows you to test an import without actually committing the transaction) |
OverwriteExisting | [Optional] If a document with the same name already exists, it will be skipped by default |
DeletePackageOnCompletion | [Optional] Removes the migration package that you’re importing from on successful completion of the import |
SuccessCallbackUri=VALUE | [Optional] A webhook URL you can add if you wish to be notified on successful completion of the migration task (Your Octopus Server will call this URL using a GET request, appending the packageId and packageVersion to the URL) |
FailureCallbackUri=VALUE | [Optional] A webhook URL you can add if you wish to be notified on failure of the migration task (Your Octopus Server will call this URL using a GET request) |
TaskId | [Response only] This will be populated with the TaskId that gets queued for this migration |
Examples
Raw request
You can trigger a request however you prefer, using curl, Fiddler, or your tool of choice…
Partial export
Request Method: POST
Request URL: https://YOUR_SOURCE_OCTOPUS_SERVER/api/migrations/partialexport
Request Headers:
- Content-Type: application/json
- X-Octopus-ApiKey: API-YOUR-SOURCE-KEY
Request Body:
{
"PackageId": "MyAwesomeOctopusMigration",
"PackageVersion": "1.0.0",
"Password": "Demo1234",
"Projects": ["First Project", "Second Project"],
"EncryptPackage": true,
"IncludeTaskLogs": true,
"DestinationApiKey": "API-YOUR-DESTINATION-KEY",
"DestinationPackageFeed": "https://YOUR_DESTINATION_OCTOPUS_SERVER"
}
Import
Request Method: POST
Request URL: https://YOUR_DESTINATION_OCTOPUS_SERVER/api/migrations/import
Request Headers:
- Content-Type: application/json
- X-Octopus-ApiKey: API-YOUR-DESTINATION-KEY
Request Body:
{
"PackageId": "MyAwesomeOctopusMigration",
"PackageVersion": "1.0.0",
"Password": "Demo1234",
"IsDryRun": "true", // Only set this to false when you've reviewed the dry run and are happy to proceed with the migration for real.
"IsEncryptedPackage": true,
}
Spaces
If you are using the Spaces feature of Octopus Deploy on the source server, you should supply the appropriate SpaceID values in the example below. The destination Space cannot be specified; it will match the Source. There are two values to supply:
- The location to look for the Projects in the source Space.
- The Space that has the feed we’ll be pushing the exported package to.
If you are not using the Spaces feature, you do not need to supply the SpaceID values.
Octopus.Clients example
The Octopus.Clients library can also help you run a migration.
Here’s an example showing you how that might look, performing a partial-export
from a source server and sending it to a destination server, then automatically running the associated import
on the destination server:
Add-Type -Path 'YOUR_LOCAL_PATH\Octopus.Client.dll'
$sourceOctopusURI = 'https://SOURCE_OCTOPUS_SERVER'
$sourceApikey = 'API-YOUR-SOURCE-KEY'
$destinationOctopusURI = 'https://DESTINATION_OCTOPUS_SERVER'
$destinationApikey = 'API-YOUR-DESTINATION-KEY'
# Spaces related
$sourceSpaceId = 'Spaces-1'
$destinationPackageFeedSpaceId = 'Spaces-1'
$migrationPackageId = 'MyAwesomeOctopusMigration'
$migrationPackageVersion = '1.0.0'
$migrationPassword = 'Demo1234'
$isDryRun = $true # Only set this to false when you've reviewed the dry run and are happy to proceed with the migration for real.
$sourceEndpoint = New-Object Octopus.Client.OctopusServerEndpoint $sourceOctopusURI,$sourceApikey
$sourceRepository = New-Object Octopus.Client.OctopusRepository $sourceEndpoint
$migrationExportResource = new-object Octopus.Client.Model.Migrations.MigrationPartialExportResource
$migrationExportResource.PackageId = $migrationPackageId
$migrationExportResource.PackageVersion = $migrationPackageVersion
$migrationExportResource.Password = $migrationPassword
$migrationExportResource.Projects = @('First Project', 'Second Project')
$migrationExportResource.IgnoreCertificates = $false
$migrationExportResource.IgnoreMachines = $false
$migrationExportResource.IgnoreDeployments = $false
$migrationExportResource.IgnoreTenants = $false
$migrationExportResource.IncludeTaskLogs = $true
$migrationExportResource.EncryptPackage = $true
$migrationExportResource.DestinationPackageFeed = $destinationOctopusURI
$migrationExportResource.DestinationApiKey = $destinationApikey
$migrationExportResource.SpaceId = $sourceSpaceId
$migrationExportResource.DestinationPackageFeedSpaceId = $destinationPackageFeedSpaceId
$migrationExportResource = $sourceRepository.Migrations.PartialExport($migrationExportResource)
Write-Host("Export task queued: $($migrationExportResource.TaskId)")
$migrationExportTask = $sourceRepository.Tasks.Get($migrationExportResource.TaskId);
if ($migrationExportTask -eq $null) {
Write-Host ("Export failed. You'll need to investigate.")
Exit
}
# Now we can poll this migration task to know when our export is complete #ScriptingFTW
Write-Host("Export task: $($migrationExportTask.Id)")
while($migrationExportTask -and ($migrationExportTask.State -eq 'Queued' -or $migrationExportTask.State -eq 'Executing' -or $migrationExportTask.State -eq 'Cancelling')){
Write-Host("Export task status: $($migrationExportTask.State). Re-checking in 5 seconds...")
start-sleep -s 5
$migrationExportTask = $sourceRepository.Tasks.Get($migrationExportTask.Id);
}
Write-Host("Export task completed: $($migrationExportTask.State)")
if ($migrationExportTask.State -ne 'Success' -or $migrationExportTask.HasWarningsOrErrors -eq $true) {
Write-Host ("Export failed or has warnings/errors. You'll need to investigate.")
Exit
}
# From here, we can proceed with an import on our destination server.
$destinationEndpoint = New-Object Octopus.Client.OctopusServerEndpoint $destinationOctopusURI,$destinationApikey
$destinationRepository = New-Object Octopus.Client.OctopusRepository $destinationEndpoint
$migrationImportResource = new-object Octopus.Client.Model.Migrations.MigrationImportResource
$migrationImportResource.PackageId = $migrationPackageId
$migrationImportResource.PackageVersion = $migrationPackageVersion
$migrationImportResource.Password = $migrationPassword
$migrationImportResource.IsDryRun = $isDryRun
$migrationImportResource.IsEncryptedPackage = $true
$migrationImportResource.DeletePackageOnCompletion = $true # May as well clean up after ourselves.
$migrationImportResource = $destinationRepository.Migrations.Import($migrationImportResource)
Write-Host("Import task queued: $($migrationExportResource.TaskId)")
$migrationImportTask = $destinationRepository.Tasks.Get($migrationImportResource.TaskId);
if ($migrationImportTask -eq $null) {
Write-Host ("Import failed. You'll need to investigate.")
Exit
}
# Now we can poll this migration task to know when our import is complete.
Write-Host("Import task: $($migrationImportTask.Id)")
while($migrationImportTask -and ($migrationImportTask.State -eq 'Queued' -or $migrationImportTask.State -eq 'Executing' -or $migrationImportTask.State -eq 'Cancelling')){
Write-Host("Import task status: $($migrationImportTask.State). Re-checking in 5 seconds...")
start-sleep -s 5
$migrationImportTask = $destinationRepository.Tasks.Get($migrationImportTask.Id);
}
Write-Host("Import task completed: $($migrationImportTask.State)")
if ($migrationImportTask.State -ne 'Success' -or $migrationImportTask.HasWarningsOrErrors -eq $true) {
Write-Host ("Import failed or has warnings/errors. You'll need to investigate.")
Exit
}
Write-Host ("Migration complete, #GreatSuccess")
Troubleshooting
We do our best to log information and warnings to your task logs during a migration. An API migration follows the same path as a manual migration using Migrator.exe command line tools behind the scenes, so if you are having difficulty running migrations, be sure to check your task logs for information that might help.
Help us continuously improve
Please let us know if you have any feedback about this page.
Page updated on Tuesday, June 25, 2024