mirror of https://github.com/pulumi/pulumi.git
db67d58b74
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 |
||
---|---|---|
.. | ||
diff.stderr.txt | ||
diff.stdout.txt | ||
eventstream.json | ||
progress.stderr.txt | ||
progress.stdout.txt |