pulumi/pkg/engine/lifecycletest/testdata/output/TestUntargetedSameStepsAcce.../0
Will Jones db67d58b74
Don't copy deleted dependencies of untargeted resources (#17743)
When using `--target` to target specific resources during an update, we
use the list of targets to decide which steps to generate given a set of
resource registrations. Specifically:

* If the registration event names a resource that is targeted, we
process it as usual.
* If the registration event names a resource that _is not_ targeted, we
emit a `SameStep` for it.

In the latter case, the emission of a `SameStep` means that the old
state for the resource will be copied across to the new state. This is
the desired behaviour -- the resource was not targeted and so the new
state should contain the resource exactly as it was prior to the update.
In #16247, this behaviour was extended so that any *dependencies* of a
resource being copied were *also* `SameStep`ped, to avoid copying over
states referring to resources no longer registered by the program (and
thus not already implicitly in the new state -- see #16247 for a
concrete example).

Manually traversing dependencies in this manner introduces a new bug
however -- by walking "back up" the state as step generation is
proceeding, we are able to observe certain intermediate states that we
would not be able to ordinarily. One such intermediate state is that of
resources which are marked for deletion as part of a
create-before-replace operation. Consider the following starting
program/state:

```typescript
const p = new Resource("parent")
const a = new Resource("a", { parent: p })
const b = new Resource("b", { dependency: a })
```

We have three resources in our state: `p`, `a` (whose URN will be
something like `p$a` since it has `p` as its parent and will thus embed
`p`'s type in its URN), and `b`. We change the program as follows:

```typescript
const p = new Resource("parent")
const a = new Resource("a", { aliases: [new Alias({ parent: p })] })
const b = new Resource("b", { dependency: a })
```

We have modified `a` to no longer have `p` as a parent and added an
alias to the URN it would have had when `p` *was* its parent. With this
change made, we run a *targeted* update that *only targets `a`*.
Moreover, as part of this update, the following will occur:

* `a` will be diffed and found to be needing *replacement*;
* The replacement will be a "create-before-replace", meaning that a new
A will be created *before* the old A is deleted;
* As part of this operation, the creation of the new A will succeed,
while the deletion of the old A will fail.

As a result, the operation unfolds thus:

* A resource registration is received for `p`. `p` is not targeted, so a
`SameStep` is emitted for it.
* A resource registration is received for `a`, with no parent and an
alias. The alias means that the old `a` with URN of the form `p$a` will
be found and become `a`'s `old` during step generation.
* `a` is targeted, so we diff it and find we must perform a
create-before-replace.
* A new `a`, with the parentless URN, is created successfully.
* The old `a`, with the parented (`p$a`) URN (since the alias enabled us
to find this), is marked for deletion -- its `Delete` field is set to
`true`. This permits Pulumi to retry deletions of replaced resources
should they fail.
* Indeed, this deletion fails, so the old `a` (with `Delete: true`) will
be left in the state to be cleaned up in a subsequent operation.
* A resource registration is received for `b`. `b` is not targeted, so a
`SameStep` is emitted for it. Prior to this however, `b`'s dependencies
are traversed so that `SameStep`s can be emitted for them as part of
#16247.
* `b`'s dependencies contain a reference to *`a`'s old URN* (of the form
`p$a`).
* Ordinarily, this URN would be *normalized* (rewritten to the new URN)
as part of snapshot persistence -- this happens to all resources,
targeted or not, if aliased resources are targeted as part of an
operation.
* In this case however, we are manually traversing dependencies prior to
snapshot persistence and so can observe the old resource (which is now
marked for deletion with `Delete: true`).
* We emit a `SameStep` for the old `a`, which causes a panic since
`SameStep`s are not supposed to be constructed for `Delete`d resources.

Despite the wordy explanation, the fix is (it seems) straightforward --
just as we skip `Delete`d resources when building the list of `old`s
that will take part in step generation, we skip them when we encounter
them as we manually traverse dependencies. The snapshot persistence
layer then takes care of them later on, copying them over. Note that
they are copied over *after* the resources that supposedly depend on
them, but due to URN normalization, those resources will be rewritten to
have their dependencies point to the new, renamed resources, which
*will* appear *before* them as is necessary.

Fixes #17713
2024-11-13 09:36:15 +00:00
..
diff.stderr.txt Don't copy deleted dependencies of untargeted resources (#17743) 2024-11-13 09:36:15 +00:00
diff.stdout.txt Don't copy deleted dependencies of untargeted resources (#17743) 2024-11-13 09:36:15 +00:00
eventstream.json Don't copy deleted dependencies of untargeted resources (#17743) 2024-11-13 09:36:15 +00:00
progress.stderr.txt Don't copy deleted dependencies of untargeted resources (#17743) 2024-11-13 09:36:15 +00:00
progress.stdout.txt Don't copy deleted dependencies of untargeted resources (#17743) 2024-11-13 09:36:15 +00:00