Moving Pulumi Resources from one project to another

Learn how to painlessly transfer Pulumi resources between projects.

Moving Pulumi Resources from one project to another

Moving Pulumi resources from one project to another can be a complex process. If you've ever found yourself navigating this challenge, worry not; I've compiled a step-by-step guide that can serve as a lifeline for anyone in a similar situation.

Target the Pulumi Project:

Begin by selecting the Pulumi project that you wish to export resources from. To do this, use the following command:

pulumi stack select

Export Resources:

Next, export all the resources from your selected stack into a JSON file. Use the following command:

pulumi stack export --file test.json

Normalize the Exported File:

To ensure a cleaner and more manageable format, copy the provided PowerShell script into your project and run it.

Note that you should replace 'test.json' in line 1 with the actual filename used for export:

$file = 'test.json'
# Read the JSON file and convert it to an object
$jsonData = Get-Content -Path $file | ConvertFrom-Json
$resources = $jsonData.deployment.resources
$convertedResources = New-Object System.Collections.ArrayList

# Loop through each resource and delete it
foreach ($resource in $resources) {

    Write-Host "Processing resource: $($resource.id)"
    # Check if the "id" property exists and its value starts with "subscription"
    if ($null -ne $resource.PSObject.Properties["id"] -and $resource.id.StartsWith("/subscription")) {
    
        # Split the string by "::" and get the last part
        $parts = $resource.urn -split "::"
        $name = $parts[-1]

        $nResource = [PSCustomObject]@{
            type = $resource.type
            id   = $resource.id
            name = $name
        }
        $convertedResources.Add($nResource)
    }
}

$fileName = Split-Path -Path $file -Leaf
$convertedResources | ConvertTo-Json | Set-Content -Path ($fileName + "-normalized.json")

normalize-export.ps1

Run the above PowerShell script

./normalize-export.ps1

Review and Customize:

After running the script, examine the 'export.json-normalized.json' file. Here, you can remove any resources that you do not intend to import into the new project.

Import Resources into the New Project:

In your new project, select the stack where you want to import the resources. Repeat the entire process for each stack you need to import by using the following command:

pulumi import -f test.json-normalized.json

Verify Changes:

Once you've completed the import process, execute a 'pulumi preview' in your new project. This should indicate minimal to no changes.

Cleanup the Old Project:

To finalize the migration, remove the resource state from the old project. You can use the provided script, ensuring that you set the project name and stack name within the file.

These values are crucial for building pulumi URNs. The script only outputs the necessary commands, but you can modify it to execute them for you.

# Pulumi stack name
$project = "old-project-name"
$stackName = "dev"
# Path to the JSON file containing a list of resource names to delete
$jsonFile = "./to-remove/$stackName.json"

# Check if the JSON file exists
if (-not (Test-Path $jsonFile -PathType Leaf)) {
    Write-Host "Error: JSON file '$jsonFile' not found."
    exit 1
}

# Read the JSON file and convert it to an object
$jsonData = Get-Content -Path $jsonFile | ConvertFrom-Json
$resources = $jsonData.resources
$reversedResources = @()
for ($i = ($resources.Count - 1); $i -ge 0; $i--) {
    $reversedResources += $resources[$i]
}

# Confirm with the user before proceeding
$resourceNames = $reversedResources | ForEach-Object { $_.name }
# Confirm with the user before proceeding
$confirmation = Read-Host "This will delete the following resources from the Pulumi stack '$stackName': $($resourceNames -join ', '). Are you sure you want to continue? (y/n)"
if ($confirmation -ne "y") {
    Write-Host "Operation canceled."
    exit 0
}

# Loop through each resource and delete it
foreach ($resource in $reversedResources) {
    $resourceType = $resource.type
    $resourceName = $resource.name

    # Construct the resource identifier (you might need to adjust this based on your actual naming conventions)
    $resourceIdentifier = "urn:pulumi:$stackName::$project::$resourceType::$resourceName"

    Write-Host pulumi state delete $resourceIdentifier
    # pulumi state delete $resourceIdentifier
}

Write-Host "Resources successfully deleted from the stack."

remove-resources.ps1

That's it! Hopefully, this guide will save you valuable time during your resource migration process.