Clone Tenant
Octopus.Script exported 08/23/2021 by benjimac93 belongs to 'Octopus' category.
Clone an Octopus tenant. The project connections and tenant tags will be cloned and the non-sensitive variables can optionally be cloned.
Parameters
When steps based on the template are included in a project's deployment process, the parameters below can be set.
Octopus URL
The URL of the Octopus Server to clone the tenant to.
Octopus API Key
The Octopus API Key to use for the API requests
Id of Tenant to Clone
The Id of the tenant to clone. This will be in the format of Tenants-1
New Tenant Name
The name of the tenant to create. Note this must be unique
Clone Variables?
Flag indicating whether the source tenant's variables should be cloned to the new tenant. Note this does not copy sensitive variables
Clone Tags?
Flag indicating whether the source tenant's tags should be cloned.
Space Id
The Id of the Space used to clone the tenant. Leave blank if you are using an Octopus version earlier than 2019.1 or if you wish to use the Octopus.Space.Id variable value.
Script body
$securityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12
[Net.ServicePointManager]::SecurityProtocol = $securityProtocol
$octopusBaseUrl = $CloneTenantStep_OctopusUrl.Trim('/')
$apiKey = $CloneTenantStep_ApiKey
$tenantToClone = $CloneTenantStep_TenantIdToClone
$tenantName = $CloneTenantStep_TenantName
$cloneVariables = $CloneTenantStep_CloneVariables
$cloneTags = $CloneTenantStep_CloneTags
$spaceId = $CloneTenantStep_SpaceId
$ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($octopusBaseUrl)) {
throw "The step parameter 'Octopus Base Url' was not found. This step requires the Octopus Server URL to function, please provide one and try again."
}
if ([string]::IsNullOrWhiteSpace($apiKey)) {
throw "The step parameter 'Octopus API Key' was not found. This step requires an API Key to function, please provide one and try again."
}
if ([string]::IsNullOrWhiteSpace($tenantToClone)) {
throw "The step parameter 'Id of Tenant to Clone' was not found. Please provide one and try again."
}
if ([string]::IsNullOrWhiteSpace($tenantName)) {
throw "The step parameter 'New Tenant Name' was not found. Please provide one and try again."
}
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
}
function Test-SpacesApi {
Write-Verbose "Checking API compatibility";
$rootDocument = Invoke-OctopusApi 'api/';
if($rootDocument.Links -ne $null -and $rootDocument.Links.Spaces -ne $null) {
Write-Verbose "Spaces API found"
return $true;
}
Write-Verbose "Pre-spaces API found"
return $false;
}
if([string]::IsNullOrWhiteSpace($spaceId)) {
if(Test-SpacesApi) {
$spaceId = $OctopusParameters['Octopus.Space.Id'];
if([string]::IsNullOrWhiteSpace($spaceId)) {
throw "This step needs to be run in a context that provides a value for the 'Octopus.Space.Id' system variable. In this case, we received a blank value, which isn't expected - please reach out to our support team at https://help.octopus.com if you encounter this error or try providing the Space Id parameter.";
}
}
}
$apiPrefix = "api/"
$tenantUrlBase = @($octopusBaseUrl, 'app#')
if ($spaceId) {
$apiPrefix += $spaceId
$tenantUrlBase += $spaceId
}
Write-Host "Fetching source tenant"
$tenant = Invoke-OctopusApi "$apiPrefix/tenants/$tenantToClone"
$sourceTenantId = $tenant.Id
$sourceTenantName = $tenant.Name
$tenant.Id = $null
$tenant.Name = $tenantName
if ($cloneTags -ne $true) {
Write-Host "Clearing tenant tags"
$tenant.TenantTags = @()
}
Write-Host "Creating new tenant"
$newTenant = Invoke-OctopusApi "$apiPrefix/tenants" -Method Post -Body $tenant
if ($cloneVariables -eq $true) {
Write-Host "Cloning variables"
$variables = Invoke-OctopusApi $tenant.Links.Variables
$variables.TenantId = $newTenant.Id
$variables.TenantName = $tenantName
Invoke-OctopusApi $newTenant.Links.Variables -Method Put -Body $variables | Out-Null
}
$tenantUrl = ($tenantUrlBase + "tenants" + $newTenant.Id + "overview") -join '/'
$sourceTenantUrl = ($tenantUrlBase + "tenants" + $sourceTenantId + "overview") -join '/'
Write-Highlight "New tenant [$tenantName]($tenantUrl) has been cloned from [$sourceTenantName]($sourceTenantUrl)"To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.
Show JSON{
"Id": "3b0f8df0-93b8-44eb-86dd-264d1283ae70",
"Name": "Clone Tenant",
"Description": "Clone an Octopus [tenant](https://octopus.com/docs/deployment-patterns/multi-tenant-deployments). The project connections and tenant tags will be cloned and the non-sensitive variables can optionally be cloned.",
"Version": 4,
"ExportedAt": "2021-08-23T12:40:10.975Z",
"ActionType": "Octopus.Script",
"Author": "benjimac93",
"Packages": [],
"Parameters": [
{
"Id": "cbedd129-210e-4bab-a446-3f89192653c7",
"Name": "CloneTenantStep_OctopusUrl",
"Label": "Octopus URL",
"HelpText": "The URL of the Octopus Server to clone the tenant to.",
"DefaultValue": "#{if Octopus.Web.ServerUri}#{Octopus.Web.ServerUri}#{else}#{Octopus.Web.BaseUrl}#{/if}",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "ea2614f0-bd41-4011-b263-7d2b12af5977",
"Name": "CloneTenantStep_ApiKey",
"Label": "Octopus API Key",
"HelpText": "The Octopus API Key to use for the API requests",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "b29e27fb-362e-45e2-a244-6d590875fb68",
"Name": "CloneTenantStep_TenantIdToClone",
"Label": "Id of Tenant to Clone",
"HelpText": "The Id of the tenant to clone. This will be in the format of *Tenants-1*",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "b9b3a6c7-6c83-4a79-9a94-febc6c5818d3",
"Name": "CloneTenantStep_TenantName",
"Label": "New Tenant Name",
"HelpText": "The name of the tenant to create. *Note this must be unique*",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "be821ad4-b195-4b11-81c2-f432ff05b86d",
"Name": "CloneTenantStep_CloneVariables",
"Label": "Clone Variables?",
"HelpText": "Flag indicating whether the source tenant's variables should be cloned to the new tenant. *Note this does not copy sensitive variables*",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "831db28c-edc2-496b-b082-e6de827ca5df",
"Name": "CloneTenantStep_CloneTags",
"Label": "Clone Tags?",
"HelpText": "Flag indicating whether the source tenant's tags should be cloned.",
"DefaultValue": "True",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "f9320a59-9752-43a5-b46a-a4d1486cfced",
"Name": "CloneTenantStep_SpaceId",
"Label": "Space Id",
"HelpText": "The Id of the Space used to clone the tenant. **Leave blank if you are using an Octopus version earlier than 2019.1 or if you wish to use the Octopus.Space.Id variable value.**",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
}
],
"Properties": {
"Octopus.Action.Script.ScriptSource": "Inline",
"Octopus.Action.Script.Syntax": "PowerShell",
"Octopus.Action.Script.ScriptBody": "$securityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12\n[Net.ServicePointManager]::SecurityProtocol = $securityProtocol\n\n$octopusBaseUrl = $CloneTenantStep_OctopusUrl.Trim('/')\n$apiKey = $CloneTenantStep_ApiKey\n$tenantToClone = $CloneTenantStep_TenantIdToClone\n$tenantName = $CloneTenantStep_TenantName\n$cloneVariables = $CloneTenantStep_CloneVariables\n$cloneTags = $CloneTenantStep_CloneTags\n$spaceId = $CloneTenantStep_SpaceId\n\n$ErrorActionPreference = 'Stop'\n\nif ([string]::IsNullOrWhiteSpace($octopusBaseUrl)) {\n throw \"The step parameter 'Octopus Base Url' was not found. This step requires the Octopus Server URL to function, please provide one and try again.\"\n}\n\nif ([string]::IsNullOrWhiteSpace($apiKey)) {\n throw \"The step parameter 'Octopus API Key' was not found. This step requires an API Key to function, please provide one and try again.\"\n}\n\nif ([string]::IsNullOrWhiteSpace($tenantToClone)) {\n throw \"The step parameter 'Id of Tenant to Clone' was not found. Please provide one and try again.\"\n}\n\nif ([string]::IsNullOrWhiteSpace($tenantName)) {\n throw \"The step parameter 'New Tenant Name' was not found. Please provide one and try again.\"\n}\n\nfunction Invoke-OctopusApi {\n param(\n [Parameter(Position = 0, Mandatory)]$Uri,\n [ValidateSet(\"Get\", \"Post\", \"Put\", \"Delete\")]$Method = 'Get',\n $Body\n )\n \n $uriParts = @($octopusBaseUrl, $Uri.TrimStart('/')) \n $uri = ($uriParts -join '/')\n\n Write-Verbose \"Uri: $uri\"\n \n $requestParameters = @{\n Uri = $uri\n Method = $Method\n Headers = @{ \"X-Octopus-ApiKey\" = $apiKey }\n UseBasicParsing = $true\n }\n \n if ($null -ne $Body) { $requestParameters.Add('Body', ($Body | ConvertTo-Json -Depth 10)) }\n \n return Invoke-WebRequest @requestParameters | % Content | ConvertFrom-Json\n}\n\nfunction Test-SpacesApi {\n\tWrite-Verbose \"Checking API compatibility\";\n\t$rootDocument = Invoke-OctopusApi 'api/';\n if($rootDocument.Links -ne $null -and $rootDocument.Links.Spaces -ne $null) {\n \tWrite-Verbose \"Spaces API found\"\n \treturn $true;\n }\n Write-Verbose \"Pre-spaces API found\"\n return $false;\n}\n\nif([string]::IsNullOrWhiteSpace($spaceId)) {\n\tif(Test-SpacesApi) {\n \t$spaceId = $OctopusParameters['Octopus.Space.Id'];\n \tif([string]::IsNullOrWhiteSpace($spaceId)) {\n \tthrow \"This step needs to be run in a context that provides a value for the 'Octopus.Space.Id' system variable. In this case, we received a blank value, which isn't expected - please reach out to our support team at https://help.octopus.com if you encounter this error or try providing the Space Id parameter.\";\n \t}\n\t}\n}\n\n$apiPrefix = \"api/\"\n$tenantUrlBase = @($octopusBaseUrl, 'app#')\n\nif ($spaceId) {\n\t$apiPrefix += $spaceId\n $tenantUrlBase += $spaceId\n}\n\nWrite-Host \"Fetching source tenant\"\n$tenant = Invoke-OctopusApi \"$apiPrefix/tenants/$tenantToClone\"\n\n$sourceTenantId = $tenant.Id\n$sourceTenantName = $tenant.Name\n$tenant.Id = $null\n$tenant.Name = $tenantName\n\nif ($cloneTags -ne $true) {\n\tWrite-Host \"Clearing tenant tags\"\n $tenant.TenantTags = @()\n}\n\nWrite-Host \"Creating new tenant\"\n$newTenant = Invoke-OctopusApi \"$apiPrefix/tenants\" -Method Post -Body $tenant\n\nif ($cloneVariables -eq $true) {\n\tWrite-Host \"Cloning variables\"\n $variables = Invoke-OctopusApi $tenant.Links.Variables\n $variables.TenantId = $newTenant.Id\n $variables.TenantName = $tenantName\n\n Invoke-OctopusApi $newTenant.Links.Variables -Method Put -Body $variables | Out-Null\n}\n\n$tenantUrl = ($tenantUrlBase + \"tenants\" + $newTenant.Id + \"overview\") -join '/'\n$sourceTenantUrl = ($tenantUrlBase + \"tenants\" + $sourceTenantId + \"overview\") -join '/'\n\nWrite-Highlight \"New tenant [$tenantName]($tenantUrl) has been cloned from [$sourceTenantName]($sourceTenantUrl)\""
},
"Category": "Octopus",
"HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates/clone-tenant.json",
"Website": "/step-templates/3b0f8df0-93b8-44eb-86dd-264d1283ae70",
"Logo": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1QTFRFT6Tl////L5Pg8vj9Y67omsvwPJrisdfzfbzs5fL7y+T32Ov5isLucLXqvt31CJPHWwAABMJJREFUeNrs3deW4jAMAFDF3U75/89dlp0ZhiU4blJEjvQ8hYubLJsA00UCBCIQgQhEIAIRiEAEIhCBCEQgAhGIQAQiEIEIhD8kJm+t+QprfdKfB9HbYpx6CWfspj8HMi+gMgHL/AmQA8W3JTKH+ALFvzCeL0RbpyoCPE9IJeNOSQwh5Z3qd6yRGWQ2qi2cZQWxqj1WzQYSjeoJmJlAklOd4VlArOqPhQEkqBERToeMcfRJBkC0Uep8CfBpjz4JsHJ0zF3dkEWNje0kiB/sUC6eApndaIiCMyAa1PiwJ0AWhRGJHJJQHG2dC7h1rNbO1QOxSA7lNCkkKrQIpJCAB1GREILYIC1NAiwbpKFJgGWDNExcwGstfExcZBCHC6nOglshHtmhViLIig1RNBCN7qjtW8C0Z1UvJcC1Z9XmwMBzzvobmgAyEzgq91dtEEsBsQSQQAFZCSBAATEEEApHZbrVBIkkEIUPSVeB+KtALA0kXQUSrwKZBCIQBnk8Y4i5CsReBeKvkqLM+BCSDWJlrZFvGk9SRTHshkgjZCGAaArIxm3H3grhVzFlW2msfl1ca79UJ1bofYvsDHHlNdTZnlh5MghuPd5NdBDUNZHyCkfktIh03XzALGRPlBDPac7qgWjHZzWcmF5zmmkhidMQ6boKiDXcDTUEaylZqCGJ0Vjvu/fLJtHqhSANEvqb2OYqkOUqEHuVMbJcZdZCGiPhKhC4yjqiIjEE7XThMp8fAWII3mY3kUIQD+AMKQTzPiBhgQ63HlT/KSvgtoi0dq5mCPah1UIE0eh3sT0NhOByvKeAkFzi8PgQomumFhsyOxpIzZN4gLOj5plVwNpR0b2AuePWKBEHQu24pSsJA+LVCeHHQxZ1SiyDIdqok8IOhSSnTottHEQTdyt4ettAj4KkzA4dMikk2Dht2S5ptm1vswnPDxn0YyDZ5oDM3iToo2T5voWaYe+Q+vdjH80QyAzZhCgcDtLMI1Tmtz9w++XHgziHQHJJu/OZ3bs9Xn8gQ72NcP3dKqEfkp10F51xhoIi2I91R+LurXV/5q7pH+wx061CzO16oSQleMyr8fXvwMA0Pro8432DPD/ySx8XrHfSuDAM8n6UhnjQabaiXf5Bq/lREHvEeNtn1rJ08+C/uXkQZHeguxAPC3UvtcJYUogLzZX5hhZZvS6onG5lxXtzWGaygwb79vT/IXhdlNibwlKYOR6T8xjI7W8n+xV7T+GH4tMzWwR+lZhRkJYSsC0thpmCYqyngOz3rN2FLBZ2wZflBCggUHF0Vnp88JKienzIXLSEZCZqU7IKr/gQW9yx3pzV7Y9kvWZWTRRIqDmTtRUnU7b2lLcTYmoqHqnmiO1poER0SPkAeZMAZxaJx0Y3TCdAclsIqDz03ALcyxfTCZBsthoGXWmigGyVhWPLFJJfuuKQWycoEFdXbH4dJJoJxNR1eD/kshz6yn48cF8yW8sFoitflB1w6Q8n+/15Za7oA17/pYNmYgP5fmWm8L1NOHPWgK8kuFew1/JXtOA0yJCv7ah7X8ObUuT5kObU30+fDZm8+zqP+HTIpK0xQ796b5Kv2hSIQAQiEIEIRCACEYhABCIQgQhEIAIRiEAEIpBf8UeAAQAEjtYmlDTcCgAAAABJRU5ErkJggg==",
"$Meta": {
"Type": "ActionTemplate"
}
}Provided under the Apache License version 2.0.