The ResourceOptions in Pulumi are not just for configuration; they’re the primary mechanism for defining the lifecycle and relationships of your infrastructure.
Let’s see ResourceOptions in action, defining a simple S3 bucket and then overriding some of its default behavior.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// Define a default bucket with standard options
const defaultBucket = new aws.s3.Bucket("my-default-bucket");
// Define a bucket with specific options
const customBucket = new aws.s3.Bucket("my-custom-bucket", {
// This is where ResourceOptions come into play
options: {
// Explicitly set the provider for this resource
provider: aws.Provider.default({ region: "us-west-2" }),
// Set a custom parent for dependency management
parent: defaultBucket,
// Define a lifecycle rule for object versioning
versioning: {
enabled: true,
},
// Ensure this bucket is deleted before other resources that depend on it
deleteBeforeReplace: true,
// Add tags for organization
tags: {
Environment: "Production",
ManagedBy: "Pulumi",
},
// Import an existing resource (if needed)
// import: "arn:aws:s3:::my-existing-bucket",
// Set a custom name for the underlying AWS resource
// name: "my-specific-s3-bucket-name",
// Set a custom urn for internal Pulumi referencing
// urn: "urn:pulumi:dev::my-project::aws:s3/bucket:Bucket::my-custom-bucket-custom-urn",
}
});
// Export the bucket names
export const defaultBucketName = defaultBucket.id;
export const customBucketName = customBucket.id;
The core problem ResourceOptions solves is managing the complexity of cloud infrastructure provisioning. Instead of just declaring "I want an S3 bucket," you can specify how you want it created, where it should live, what its dependencies are, and how it should be updated or deleted. This allows for fine-grained control over infrastructure state.
Let’s break down the key ResourceOptions and their implications:
-
provider: This explicitly associates a resource with a specific cloud provider instance. This is crucial when you’re managing resources across multiple accounts, regions, or even different cloud providers within a single Pulumi program. If not specified, Pulumi uses the default provider configured for the current stack.- Example Usage:
provider: new aws.Provider("aws-east", { region: "us-east-1" }) - Why it Matters: Ensures resources land in the intended environment, preventing accidental deployments to the wrong region or account.
- Example Usage:
-
parent: This establishes a parent-child relationship between resources. Pulumi uses this to determine deployment order and dependency graphs. A child resource will typically be created after its parent. If the parent is deleted, Pulumi will also attempt to delete the child.- Example Usage:
parent: vpc(wherevpcis another Pulumi resource) - Why it Matters: Guarantees that dependent resources are provisioned or deprovisioned in the correct sequence. For instance, you’d want a subnet to be created within a VPC.
- Example Usage:
-
dependsOn: This explicitly declares a dependency between resources that might not be implicitly captured by theparentrelationship or direct property references. Pulumi will ensure the resources independsOnare created before the current resource.- Example Usage:
dependsOn: [user, role] - Why it Matters: Essential for resources that have no direct property linkage but must exist prior to another. Think of a database needing a security group rule to allow access from an application server.
- Example Usage:
-
ignoreChanges: This tells Pulumi to not track changes to specific properties of a resource. Pulumi will still deploy the resource with its initial configuration, but if the cloud provider modifies these properties externally, Pulumi will ignore those changes and not attempt to reconcile them.- Example Usage:
ignoreChanges: ["tags", "public_access_block"] - Why it Matters: Useful for properties that are managed outside of Pulumi or that you intentionally want to be immutable after initial creation.
- Example Usage:
-
deleteBeforeReplace: When a resource needs to be replaced (e.g., changing a fundamental property like an instance type), this option dictates that the old resource should be deleted before the new one is created. This prevents naming conflicts or downtime if the resource cannot be updated in-place.- Example Usage:
deleteBeforeReplace: true - Why it Matters: Crucial for resources where in-place updates are not supported or desirable, ensuring a smooth transition.
- Example Usage:
-
import: This allows Pulumi to adopt and manage existing infrastructure that was not originally provisioned by Pulumi. You provide the cloud provider’s identifier (like an ARN or ID), and Pulumi will import it into your stack.- Example Usage:
import: "arn:aws:iam::123456789012:role/MyExistingRole" - Why it Matters: Enables gradual adoption of Pulumi into existing environments without needing to re-provision everything.
- Example Usage:
-
name: This allows you to specify a custom name for the underlying cloud resource, overriding Pulumi’s auto-generated names. This is useful for adhering to naming conventions or referencing resources by predictable names.- Example Usage:
name: "my-production-database" - Why it Matters: Provides control over resource naming for compliance, consistency, and easier identification in cloud consoles.
- Example Usage:
-
protect: Marking a resource withprotect: trueprevents it from being accidentally deleted. Pulumi will preventpulumi destroyoperations from affecting these resources and will require explicit un-protection before deletion.- Example Usage:
protect: true - Why it Matters: A safeguard against accidental deletion of critical infrastructure like production databases or core networking components.
- Example Usage:
-
retainOnDelete: Similar toprotect, but instead of preventing deletion, it ensures that the resource’s state is retained even after it’s deleted from the cloud provider. This can be useful for auditing or if you plan to re-import the resource later.- Example Usage:
retainOnDelete: true - Why it Matters: Preserves historical data or configuration for resources that are removed from active management but might be needed for historical context.
- Example Usage:
The urn (Uniform Resource Name) is Pulumi’s internal, globally unique identifier for a resource within a Pulumi program. While you can set it manually, it’s almost always auto-generated and should not be tampered with unless you have a very specific, advanced use case, such as migrating resources between stacks or projects where you need to preserve the exact Pulumi identity.
The next step after mastering ResourceOptions is understanding how Pulumi manages state across multiple stacks and how to leverage outputs to build complex, interconnected systems.