pulumi: Allow applications to handle "not found" errors from `.get()`

Problem Scenario

It can be common to need to query for an existing resource and if it doesn’t exist then take some other action. Currently Pulumi’s <resource>.get() methods halt Pulumi execution without throwing an error that the user/application can catch and react to.

Suggestion

The results or error from <resource>.get() calls and data sources should be catchable so that users can take other actions as a result.

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 62
  • Comments: 26 (8 by maintainers)

Most upvoted comments

+1 any updates on this one? Really need the get to be “catchable”. The scenario I want to accomplish is as follows

  • use .get() to lookup the resource.
  • if the resource does not exists, there is an exception thrown,
  • Catch the exception in the catch block and create a new resource there.

Same issue here with an attempt to create k8s namespace.

Is there any progress on this one?

Give the above & https://github.com/pulumi/pulumi/issues/11275 I think we should reopen this. We’ll need to be careful to explain that this can not be used for “try get or create” logic, but it sounds like it has other applications as well.

Updated to include “and data sources” in the suggestion.

For invokes (“data sources”), you can do this today:

aws.getAmi({
    owners: ["153052954103"],
}, { async: true })
.then(
    res => console.log(`RESULT: ${res}`), 
    err => console.error(`ERROR: ${err}`)
);

That is, the error is bubbled up through the promise error handler (and as an exception in async/await code).

Another example:

async function getAmi(): Promise<string> {
    try {
        const amiDetails = await aws.getAmi({
            owners: ["153052954103"],
        }, { async: true });
        return amiDetails.id;
    } catch (err) {
        return "ami-014a2e30da708ee8b";
    }
}

This is not true for .get() calls though (which is what I will continue to track with this issue).

Is there any way to lookup for the existence of a resource without the function actually throwing an error? For context - I am trying to get getUserAssignedIdentityOutput but it errors out and the error seems to be not catchable. https://www.pulumi.com/registry/packages/azure-native/api-docs/managedidentity/getuserassignedidentity/

+1

Scenario: run a Lambda Function to create schema on an RDS Cluster only if the Cluster hasn’t existed before.

I have a similar use case which cannot be covered with “create if not exists” pattern.

const helm_postgres = new kubernetes.helm.v3.Release(
  "helm-postgres",
  // ...
  { ignoreChanges: ["checksum"] }
);

const secret_postgres = pulumi.output(
  kubernetes.core.v1.Secret.get("helm-postgres-secret", "postgres/postgres-postgresql")
);

I have a database deployed with helm, and I have to read out the secrets created by the chart to get the connection password (which is then passed to other resources I wanted to create).

+1 for that

After an investigation in #10883 and discussing the implications with @Frassle we are leaning to close this issue and recommend other Pulumi mechanisms for the use cases here:

  1. A lot of the readers coming here are interested in handling the error from get to create a resource if it does not already exist. #3388 will provide a much better way to address this scenario.

  2. There is a workaround available now before #3388 ships. Providers expose data sources allowing the program to query for existence of resources in the cloud. For an example see getSecurityGroups in AWS. The advantage of these compared to Resource.get() is that they do not interfere with Pulumi state.

  3. For use cases that need to run some logic when a resource actually gets created, lifecycle hooks (specifically create hooks) as specified in #1691 seem to be the preferable mechanism.


Technicalities from the #10338 exploration:

  • Explored building conditional creation on top of recoverable Resource.get in #10883. While it can be made to work, there are some challenges in this approach to get previews and repeated updates working correctly.

  • The engine sees Resource.tryGet()…new Resource() as two separate operations and not an atomic operation, confusing URN uniqueness tracking, requiring workarounds

  • Repeated update has to edit the resource’s record in the state to switch from the new Resource style record to a Resource.get style record (external: true), requiring workarounds to get empty previews and avoid UI glitches

Expereincing the same issue. Would like to create an AWS Config recorder (limited to 1 per account per region) and want to check if one already exists before attempting to create one.

const recorder = aws.cfg.Recorder.get('recorder', 'default'); // Halts Pulumi if it does not exist and unable to catch the error.