pulumi/pkg/engine/lifecycletest/testdata/output/TestCreateDuringTargetedUpd...
Will Jones 2aad59df18
Spot skipped-create dependencies even when inputs don't change (#17633)
`Create`s happen in response to new resources being present in a Pulumi
program but not in Pulumi's state snapshot. For instance, take the
following TypeScript program:

```typescript
const b = new Resource("b", { x: 2 })
const c = new Resource("c", { x: 3 }, { deletedWith: b })
```

When asked to run this program on an empty state with no arguments,
Pulumi will issue two `Create` calls -- one for `b`, and one for `c`.
The call for `c` will *depend on* `b`'s due to the need for
`deletedWith` to refer to `b`'s URN.

If instead of passing no arguments we ask Pulumi to perform a *targeted*
operation that *only targets `c`*, Pulumi will throw an error and refuse
to execute the program. This is because `c`'s `Create` would depend on
`b`'s `Create`, but since `b` has not been targeted, its `Create` will
not happen and thus `c`'s call cannot be built. Internally, we call
`b`'s omission a "skipped create", and keep track of these so that we
can trigger the error above appropriately.

So far, so good. Now, consider that we have executed the above program
with no targets, so that Pulumi's state contains both `b` and `c`, with
`c` depending on `b` via a `deletedWith` link. We now add the missing
`a` to the program and modify `b` to depend on it:

```typescript
const a = new Resource("a", { x: 1 })
const b = new Resource("b", { x: 2 }, { deletedWith: a })
const c = new Resource("c", { x: 3 }, { deletedWith: b })
```

If we were to run the program with no targets, we would expect a state
in which all of `a`, `b` and `c` existed. `c` would depend on `b` (as it
did before) and `b` would have a new dependency on `a`. Lovely.

Of course, we are not about to run the program with no targets. We are
instead interested in *targeting `b` only*. When we do, the following
sequence of events will unfold:

* `a`, not existing in the state already and not being targeted, will
yield a skipped create.
* `b` depends on a skipped create. However, its *inputs* have not
changed (`x` was `2` before, and it's still `2` after). Consequently,
`b` will have yielded a `SameStep`. We *incorrectly* assume this means
that skipped creates are not a problem (`SameStep`s mean no changes,
right?) and allow the deployment to proceed.
* We write the new `b` to the state, with a dependency on the skipped
create, yielding a snapshot integrity error.
* 💥

We might ask "why assume that `SameStep`s are safe?". From looking at
the existing test cases, it seems likely that this was designed to cover
the case where a skipped create is depended on *by another skipped
create* (which is internally represented as a `SameStep`) -- in such
cases, we don't need to error and the deployment can proceed. However,
this bug shows that there are cases where `SameStep` does not imply
skipped create. This commit thus tightens up the logic appropriately,
checking explicitly for `SameStep`s whose `IsSkippedCreate` method
returns true.
2024-10-30 16:17:30 +00:00
..
0 Spot skipped-create dependencies even when inputs don't change (#17633) 2024-10-30 16:17:30 +00:00
1 Spot skipped-create dependencies even when inputs don't change (#17633) 2024-10-30 16:17:30 +00:00