Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable output values by default #8014

Merged
merged 6 commits into from
Sep 24, 2021
Merged

Enable output values by default #8014

merged 6 commits into from
Sep 24, 2021

Conversation

justinvp
Copy link
Member

@justinvp justinvp commented Sep 21, 2021

Enable output values by default in the resource monitor and change the polarity of the envvar from PULUMI_ENABLE_OUTPUT_VALUES to PULUMI_DISABLE_OUTPUT_VALUES.

We've had a cron job running in the pulumi/examples repro with the feature both enabled and disabled, and everything is looking good on those runs (as expected), so we're comfortable enabling it by default.

Fixes #8007

Copy link
Member

@t0yv0 t0yv0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📿

@justinvp justinvp force-pushed the justin/outputvalues_enable branch 2 times, most recently from ea380a1 to 44d9d06 Compare September 23, 2021 18:36
Enable output values by default in the resource monitor and change the polarity of the envvar from `PULUMI_ENABLE_OUTPUT_VALUES` to `PULUMI_DISABLE_OUTPUT_VALUES`.
Marshal all unknown output values as `resource.MakeComputed(resource.NewStringProperty(""))` when not keeping output values, which is consistent with what the SDKs do.

Otherwise, when `v.OutputValue().Element` is nil, `resource.MakeComputed(v.OutputValue().Element)` will be marshaled as a null value rather than as an unknown sentinel.
Before we expanded the meaning of `resource.Output`, `MarshalProperties` always skipped output values:

```go
if v.IsOutput() {
    logging.V(9).Infof("Skipping output property for RPC[%s]: %v", opts.Label, key)
}
```

As part of expanding the meaning of `resource.Output`, I'd adjusted `MarshalProperties` to only skip output values when the value was unknown and when not keeping output values:

```go
if v.IsOutput() && !v.OutputValue().Known && !opts.KeepOutputValues {
    logging.V(9).Infof("Skipping output property for RPC[%s]: %v", opts.Label, key)
}
```

However, this doesn't work the way we want when marshaling properties that include unknown output values to a provider that does not accept outputs. In that case, `opts.KeepOutputValues` will be `false` because we want the marshaler to fall back to returning non-output-values (e.g. unknown sentinel value for unknown output values), but instead of getting the intended fallback values, the unknown output values are skipped (not what we want).

I suspect we may be able to delete the output value skipping in `MarshalProperties` altogether (it's odd that it is skipping `resource.Output` but not `resource.Computed`), but to avoid any unintended side effects of doing that, instead, this commit introduces a new `MarshalOptions.DontSkipOutputs` option that can be set to `true` to opt-in to not skipping output values when marshaling. The check in `MarshalProperties` now looks like this:

```go
if !opts.DontSkipOutputs && v.IsOutput() && !v.OutputValue().Known {
    logging.V(9).Infof("Skipping output property for RPC[%s]: %v", opts.Label, key)
}
```

`opts.DontSkipOutputs` is set to `true` when marshaling properties for calls to a provider's `Construct` and `Call`.
This commit adds support for deserializing output values, which is needed in some cases when serialized inputs are returned as outputs in the SDK.
This commit adds support for deserializing output values, which is needed in some cases when serialized inputs are returned as outputs in the SDK.
@justinvp
Copy link
Member Author

@pgavlin, @t0yv0, please take another look. Some of the existing MLC tests failed when output values were enabled by default and the subsequent commits here address the problems.

  1. When marshaling unknown output values and the KeepOutputValues option isn't set, we'd fall back to marshaling the value as if it was resource.MakeComputed(v.OutputValue().Element). However, this is not the behavior we want because that ends up being marshaled as a null value when v.OutputValue().Element is nil:

    // Finally, if a null, we can guess its value! (the one and only...)
    if elem.IsNull() {
    return MarshalNull(opts)
    }

    To address this, I've changed it to always fall back to marshaling resource.MakeComputed(resource.NewStringProperty("")) so that the marshaled value is the unknown string sentinel value (consistent with what the SDKs do).

  2. MarshalProperties was skipping v.IsOutput() property values when marshaling properties to providers that do not accept outputs. More details are in the commit message, but to address this, I've added a new MarshalOptions.DontSkipOutputs option, which is now specified when marshaling properties in the engine when calling a provider's Construct and Call.

  3. There are cases inside the Node.js and Python SDKs where the serialized inputs are deserialized and returned as outputs. When that happens, we were erroring when there were output values because we hadn't implemented the output value deserialization yet in these SDKs. I've added commits that do that.

@@ -161,12 +161,32 @@ describe("runtime", () => {
...isSecret && { secret: isSecret },
...(deps.length > 0) && { dependencies: deps },
},
expectedRoundTrip: new Output(resources,
Promise.resolve(isKnown ? tv.expected : undefined), Promise.resolve(isKnown),
Promise.resolve(isSecret), Promise.resolve([])),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last element is weird, I am guessing this corresponds to

    /** @internal */
    public constructor(
        resources: Set<Resource> | Resource[] | Resource,
        promise: Promise<T>,
        isKnown: Promise<boolean>,
        isSecret: Promise<boolean>,
        allResources: Promise<Set<Resource> | Resource[] | Resource> | undefined) {

Is it possible to skip it (default undefined)?

It's weird that the constructor has two parameters where resources can be passed in but there are probably reasons.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird that the constructor has two parameters where resources can be passed in but there are probably reasons.

Yeah, it's a little strange. It was introduced in #3680. I'm not entirely familiar with the backstory, but looks like it was done this way to address some SxS problems.

Is it possible to skip it (default undefined)?

We might be able to make it optional with a default value of undefined.

@t0yv0
Copy link
Member

t0yv0 commented Sep 24, 2021

Still looking good, read through the extra commits. Flags are getting unfortunately complex but I appreciate why this is happening.

@justinvp justinvp merged commit 3027d01 into master Sep 24, 2021
@pulumi-bot pulumi-bot deleted the justin/outputvalues_enable branch September 24, 2021 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Output values: Enable feature by default
3 participants