The pulumi import command is your secret weapon for bringing existing, unmanaged cloud infrastructure into Pulumi’s declarative state, but it’s not just about copying IDs; it’s about making Pulumi understand your resources’ current configuration.
Let’s see it in action. Imagine you have an S3 bucket that was created manually or by another tool.
# First, ensure you have a Pulumi program that declares the resource
# For example, in Python:
import pulumi
import pulumi_aws as aws
s3_bucket = aws.s3.Bucket("my-existing-bucket",
# We'll fill in the actual properties after importing
)
Now, you need the existing bucket’s ID. You can get this from the AWS console or CLI:
aws s3api list-buckets --query "Buckets[?Name=='my-existing-bucket'].Name" --output text
Once you have the bucket name (which is its ID for S3 buckets), you can run the import command. The general format is pulumi import <resource_type> <logical_name> --id <physical_id>.
pulumi import aws:s3/bucket:Bucket my-existing-bucket my-existing-bucket
After running this, Pulumi will create an import.txt file (or similar) that shows the properties it thinks the resource has. This is where the real work begins. You’ll see something like this in import.txt:
{
"urn": "urn:pulumi:dev::my-project::aws:s3/bucket:Bucket::my-existing-bucket",
"id": "my-existing-bucket",
"properties": {
"bucket": "my-existing-bucket",
"acl": "private",
"tags": {},
"versioning": {
"enabled": false
}
}
}
Your job is to take these properties and integrate them into your Pulumi program. You’ll edit your aws.s3.Bucket("my-existing-bucket", ...) resource definition to match the imported properties.
import pulumi
import pulumi_aws as aws
s3_bucket = aws.s3.Bucket("my-existing-bucket",
bucket="my-existing-bucket", # From import.txt
acl="private", # From import.txt
versioning=aws.s3.BucketVersioningArgs(
enabled=False, # From import.txt
),
# Add any other properties you want Pulumi to manage
tags={
"ManagedBy": "Pulumi",
}
)
After updating your Pulumi program, run pulumi up. Pulumi will compare your program’s desired state with the imported state and then update the cloud resource to match your program. If everything is aligned, it will report "No changes."
The core problem pulumi import solves is bridging the gap between infrastructure that exists outside of Pulumi’s management and the desired state managed by Pulumi. It allows you to gradually migrate existing infrastructure into a Pulumi-managed state without a disruptive "rip and replace." You can import resources one by one or in batches, bringing them under Pulumi’s control and enabling consistent deployments, drift detection, and automated updates.
Internally, pulumi import works by querying the cloud provider for the specified resource using its physical ID. It then serializes the resource’s current state into a JSON format. This JSON is presented to you as a starting point for your Pulumi program. When you run pulumi up after integrating these properties, Pulumi performs a diff between your program’s definition and the state it recorded during import (and the actual cloud state), generating an update plan.
The id argument in pulumi import is crucial. For many resources, this is a simple string identifier like an ARN or a name. However, for resources with composite IDs (e.g., a specific subnet within a VPC, or a resource within a parent resource), you might need to provide a more complex string, often constructed from multiple identifiers. For instance, importing a specific AWS Route 53 record set might require an ID like zoneId::name::type. Always consult the specific resource’s documentation for the expected id format.
When you import a resource that has many default properties, Pulumi’s import might not capture all of them. You’ll often see a minimal set of properties in import.txt. It’s your responsibility to inspect the actual resource in your cloud provider and update your Pulumi program with the relevant properties to ensure full parity. This means looking at things like encryption settings, lifecycle rules, access logs, and other configurations that might not be immediately obvious.
The next step after successfully importing resources and aligning your Pulumi program is understanding how Pulumi handles drift detection and updates for these imported resources.