Migrating tenants to a new Octopus Deploy target

multi-tenancy
ask-octopus
api
(Ryan Rousseau) #1

We have 50 tenants that share a target. We are retiring this target and need to migrate the tenants to the new target. What’s the best way to do this?

(Ryan Rousseau) #3

Starting state

We have two targets, “Server A” and “Server B”. We have 50 tenants that are currently hosted on Server A. Server A is being retired and we want to migrate our tenants to Server B.

Solution

First, we need to see how the current target is configured. If all of the tenants are attached individually like in the screenshot below (see the “50 tenants” chip next to Server A), we’ll need to replace that with a tenant tag first.

Let’s create a new tenant tag set. We’ll call it Hosting and create a tag for Server A and Server B.

Now let’s update our tenants to have the Server A tag. Doing this manually isn’t bad for a few tenants, but for 50, we’ll want to use a script. This following script is a starting point. You may need to add in extra logic or filtering for your case.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$octopusBaseUrl = "Your Octopus Url"
$apiKey = "Your Api Key"
$spaceId = "Your Space Id"

$ErrorActionPreference = 'Stop'

function Invoke-OctopusApi {
    param(
        [Parameter(Position = 0, Mandatory)]$Uri,
        [ValidateSet("Get", "Post", "Put", "Delete")]$Method = 'Get',
        $Body
    )

    $uriParts = @($octopusBaseUrl, $Uri.TrimStart('/'))
    $uri = ($uriParts -join '/')

    Write-Verbose "Uri: $uri"

    $requestParameters = @{
        Uri             = $uri
        Method          = $Method
        Headers         = @{ "X-Octopus-ApiKey" = $apiKey }
        UseBasicParsing = $true
    }

    if ($null -ne $Body) { $requestParameters.Add('Body', ($Body | ConvertTo-Json -Depth 10)) }

    return Invoke-WebRequest @requestParameters | ForEach-Object Content | ConvertFrom-Json
}

$apiPrefix = "api/"

if ($spaceId) {
    $apiPrefix += $spaceId
    $tenantUrlBase += $spaceId
}

$tenants = Invoke-OctopusApi "$apiPrefix/tenants/all" -Method Get

$tenants | ForEach-Object {
    $tenant = $_
    $tenant.TenantTags += "Hosting/Server A"
    Invoke-OctopusApi "$apiPrefix/tenants/$($tenant.Id)" -Method Put -Body $tenant
}

Now that all of our tenants have the appropriate tag, we can update our targets to use those tags. Doing this means we won’t have to associate each tenant to a specific target. Again, the following script is a starting point.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$octopusBaseUrl = "Your Octopus Url"
$apiKey = "Your Api Key"
$spaceId = "Your Space Id"
$targetA = "Your Target A Id"
$targetB = "Your Target B Id"

$ErrorActionPreference = 'Stop'

function Invoke-OctopusApi {
    param(
        [Parameter(Position = 0, Mandatory)]$Uri,
        [ValidateSet("Get", "Post", "Put", "Delete")]$Method = 'Get',
        $Body
    )

    $uriParts = @($octopusBaseUrl, $Uri.TrimStart('/'))
    $uri = ($uriParts -join '/')

    Write-Verbose "Uri: $uri"

    $requestParameters = @{
        Uri             = $uri
        Method          = $Method
        Headers         = @{ "X-Octopus-ApiKey" = $apiKey }
        UseBasicParsing = $true
    }

    if ($null -ne $Body) { $requestParameters.Add('Body', ($Body | ConvertTo-Json -Depth 10)) }

    return Invoke-WebRequest @requestParameters | % Content | ConvertFrom-Json
}

$apiPrefix = "api/"
$tenantUrlBase = @($octopusBaseUrl, 'app#')

if ($spaceId) {
    $apiPrefix += $spaceId
    $tenantUrlBase += $spaceId
}

$target = Invoke-OctopusApi "$apiPrefix/machines/$targetA" -Method Get

$target.TenantIds = @()
$target.TenantTags += "Hosting/Server A"

Invoke-OctopusApi "$apiPrefix/machines/$targetA" -Method Put -Body $target

$target = Invoke-OctopusApi "$apiPrefix/machines/$targetB" -Method Get

$target.TenantIds = @()
$target.TenantTags += "Hosting/Server B"

Invoke-OctopusApi "$apiPrefix/machines/$targetB" -Method Put -Body $target

Checking the infrastructure screen shows that our targets are configured correctly.

Now we’re ready for the migration!

Once the new server is ready for testing, remove the Server A tag from one of the tenants and replace it with the Server B tag. When you deploy a release for that tenant, it will go to the new server instead of the old one.

Once you’re comfortable with the new server, you can update some more tenants (or all of them) to use the Server B tag. I recommend doing this with a script similar to the first one we used. And :tada: your tenants will deploy to the new server.