Hi! It might be a stupid question, but how do I va...
# general
e
Hi! It might be a stupid question, but how do I validate a
pulumi.Input<string>
field in my constructor? Imagine the following code:
Copy 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
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
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
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
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
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
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
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):
Copy code
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
I find that a scary assumption to be honest
l
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
If I validate within an apply, pulumi.ResourceError is still the right thing to do?
l
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
I will do the string check to get as much early feedback as possible, but I will still validate Ouput ad Promise
l
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.)