Chris Smith
Chris Smith

Reputation: 18722

How to control resource creation order in Pulumi

I'm trying to create some resources and need to enforce some sort of creation order. e.g. creating an aws.s3.Bucket for storing the logs before it can be used as an input to aws.cloudfront.Distribution.

How do I control resource creation order when using Pulumi?

Upvotes: 9

Views: 10321

Answers (2)

Rotem jackoby
Rotem jackoby

Reputation: 22198

Simple answer

The official docs are quite informative about this option:

The dependsOn option provides a list of explicit resource dependency resources.

Pulumi automatically tracks dependencies between resources when you supply an input argument that came from another resource’s output properties.
In some cases, however, you may need to explicitly specify additional dependencies that Pulumi doesn’t know about, but must respect.
This might happen if a dependency is external to the infrastructure itself — such as an application dependency — or is implied due to an ordering or eventual consistency requirement.
These dependencies ensure that resource creation, update, and deletion is done in the correct order.

The examples below demonstrates making res2 dependent on res1, even if there is no property-level dependency:

#Python
res1 = MyResource("res1");
res2 = MyResource("res2", opts=ResourceOptions(depends_on=[res1]));

#Golang
res1, _ := NewMyResource(ctx, "res1", &MyResourceArgs{/*...*/})
res2, _ := NewMyResource(ctx, "res2", &MyResourceArgs{/*...*/}, pulumi.DependsOn([]Resource{res1}))

#JS
let res1 = new MyResource("res1", {/*...*/});
let res2 = new MyResource("res2", {/*...*/}, { dependsOn: [res1] });


If you want to understand what is happening under the hood

Read about creation and deletion order:

Pulumi executes resource operations in parallel whenever possible, but understands that some resources may have dependencies on other resources.
If an output of one resource is provided as an input to another, the engine records the dependency between these two resources as part of the state and uses these when scheduling operations.
This list can also be augmented by using the dependsOn resource option.

By default, if a resource must be replaced, Pulumi will attempt to create a new copy the the resource before destroying the old one.
This is helpful because it allows updates to infrastructure to happen without downtime.
This behavior can be controlled by the deleteBeforeReplace option.
If you have disabled auto-naming by providing a specific name for a resource, it will be treated as if it was marked as deleteBeforeReplace automatically (otherwise the create operation for the new version would fail since the name is in use).

Upvotes: 3

Chris Smith
Chris Smith

Reputation: 18722

Generally, Pulumi handles the ordering of resource creation automatically. In TypeScript this is even enforced by the language's type system via pulumi.Input<T> and pulumi.Output<T> types. But understanding the details of those types isn't actually necessary.

The Pulumi engine will resolve all "parameters" or "inputs" to a resource. So if you use one resource as a parameter in configuring another, the dependent resource will be created first. i.e. it works the way you would want it to.

However, there are situations where you need to explicitly mark one resource as being dependent upon another. This will happen when there is some sort of coupling that exists outside of the Pulumi program.

To specify an explicit dependency, you can provide an instance of pulumi.ResourceOptions to the resource, and set its dependsOn property. The Pulumi engine will resolve all of the resources in the dependsOn array before processing the resource.

Here's a simple example showing these two ways the Pulumi determines ordering. An AWS S3 bucket is a resource that contains files, called objects. The bucket must be created before any objects can be created inside of it.

// Create a bucket named "example-bucket", available at s3://example-bucket.
let bucket = new aws.s3.Bucket("bucket",
    {
        bucket: "example-bucket",
    });

let file1 = new aws.s3.BucketObject("file1", {
    // The bucket field of BucketObjectArgs is an instance of
    // aws.s3.Bucket. Pulumi will know to create the "bucket"
    // resource before this BucketObject resource.
    bucket: bucket,
});

let file2 = new aws.s3.BucketObject("file2",
    {
        // The bucket field of BucketObjectArgs is a string. So
        // Pulumi does not know to block creating the file2 resource
        // until the S3 bucket exists.
        bucket: "example-bucket",
    } as aws.s3.BucketArgs,
    {
        // By putting "bucket" in the "dependsOn" array here,
        // the Pulumi engine will create the bucket resource before
        // this file2 resource.
        dependsOn: [ bucket ],
    } as pulumi.ResourceOptions);

Upvotes: 11

Related Questions