https://pulumi.com logo
Title
e

echoing-address-44214

03/29/2023, 1:42 AM
Hi! It might be a stupid question, but how do I validate a
pulumi.Input<string>
field in my constructor? Imagine the following code:
class RuwenTest extends pulumi.ComponentResource {
  constructor(
    name: string,
    text: pulumi.Input<string>,
    opts?: pulumi.ComponentResourceOptions
  ) {
    super("ruwen:index:Test/Test", name, {}, opts);

    // validate if text contains foo
    pulumi.output(text).apply((t) => {
      if (t.includes("foo")) {
        throw new Error("text contains foo");
      }
    });
  }
}
Since apply is not executed in pulumi preview, I will only see the error if I actually apply the change. I want to see it early. And I struggled to unit test the error. What is the recommended approach?
l

little-cartoon-10569

03/29/2023, 1:54 AM
You can use policies, but in general, you should check your config before creating resources. Resources should be able to assume valid input. Pulumi / infra apps don't have to work the same way as user-centric apps. You don't have to check that the user typed the correct value.
99% of inputs to a resource come from other resources. If those resources are valid, then this resource is valid.
The recommended approach is: don't throw exceptions in resource constructors.
There are a couple of Pulumi exceptions you can throw in these cases, when it's appropriate.
Onesec...
e

echoing-address-44214

03/29/2023, 1:58 AM
Resources should be able to assume valid input.
I need to validate user supplied input somewhere. I can't limit everything down enough via the type system.
I can make my constructors private and wrap them around a static method so I can use async
l

little-cartoon-10569

03/29/2023, 1:59 AM
You can use pulumi.RunError or pulumi.ResouceError.
You should validate user input (which might happen in an automation-api program, but never in a normal Pulumi program) in the index.ts.
Not in the resource constructors.
Almost no validation happens. Since Pulumi programs are run by engineers based on PRs, or similar, all inputs can be safely assumed to be pre-validated.
Possibly relevant: user-supplied values won't be wrapped in outputs. Only values from other resources / stacks will be. And they can safely be assumed to be valid.
e

echoing-address-44214

03/29/2023, 2:05 AM
I won't have an end-user input, but I still have engineers supplying values which I need to validate. My current case is: We are wrapping the datadog monitor resource in order to set certain tags centrally. I still accept the original datadog monitor args (which include tags) and make sure that the centrally managed tags are not being set. So I need some code to validate
l

little-cartoon-10569

03/29/2023, 2:05 AM
Will datadog not throw that exception for you?
If the tag values are user supplied, you can validate them when you get them from the Pulumi config or similar. They won't be outputs at that point.
e

echoing-address-44214

03/29/2023, 2:06 AM
I honestly don't know. I prefer to check that myself
I got a pulumi.Input<string> type. Is there a way to check programmatically if something is an Output?
l

little-cartoon-10569

03/29/2023, 2:09 AM
That's inside the constructor. Do it in index.ts, before you pass it into the constructor. It's still a string at that point. As to your question:
pulumi.Input<string>
is
pulumi.Output<string> | string
, so you can do this (assuming you're in a constructor):
const toBeValidated = getValue();
  if (toBeValidated instanceof string) {
    if (!isValid(toBeValidated)) {
      throw new ResourceError(`${toBeValidated} is invalid.`, this);
  }
}
Typescript will nicely narrow your variables' types when you do this.
Then if it's an Output, you have to assume that it's already been validated, whenever (or ideally, before) it was passed into whatever resource it has come from.
e

echoing-address-44214

03/29/2023, 2:12 AM
I find that a scary assumption to be honest
l

little-cartoon-10569

03/29/2023, 2:12 AM
Infrastructure code has a different set of assumptions than application code. Changing assumptions is a bit scary 🙂
Check all the example code, all the Pulumi GitHub repositories. This is how infra code works.
Experience has validated these new assumptions.
e

echoing-address-44214

03/29/2023, 2:13 AM
If I validate within an apply, pulumi.ResourceError is still the right thing to do?
l

little-cartoon-10569

03/29/2023, 2:14 AM
ResourceErrors are good, they terminate the Pulumi engine loop and still allow Pulumi to tidy up and print nice messages.
Generic Errors can cause issues.
e

echoing-address-44214

03/29/2023, 2:14 AM
I will do the string check to get as much early feedback as possible, but I will still validate Ouput ad Promise
l

little-cartoon-10569

03/29/2023, 2:15 AM
Yep. But for those cases, your preview won't always catch the problem (I've found that some applys are resolved during preview; Pulumi must have clever dependency resolution and knows that some are safe to resolve even in preview.)