mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
rfc: Optimized Refresh and Detection of New Objects
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
138
rfc/20251029-optimized-refresh.md
Normal file
138
rfc/20251029-optimized-refresh.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Optimized Refresh and Detection of New Objects
|
||||
|
||||
By default, OpenTofu's "plan" phase currently includes a step of requesting the
|
||||
latest settings for every object tracked in the prior state, to check whether
|
||||
something has changed in the remote system outside of OpenTofu's workflow.
|
||||
|
||||
This extra step is useful because it ensures that OpenTofu is planning against
|
||||
the true current state of the remote objects rather than a stale snapshot of
|
||||
what was current at the end of the previous plan/apply round, but the current
|
||||
approach has some drawbacks too:
|
||||
|
||||
- The current provider protocol uses a separate call to refresh each object,
|
||||
which means that configurations that include many objects are often slow
|
||||
to refresh and may cause API rate limits to be exceeded.
|
||||
|
||||
This tends to cause those with larger configurations to use `-refresh=false`
|
||||
to completely disable refreshing, or to use the `-target=...` option
|
||||
to work with only small fragments of configuration at a time, both of
|
||||
which can cause OpenTofu to be left with an inconsistent view of the
|
||||
remote objects, potentially causing problems later.
|
||||
|
||||
- Refreshing individual objects doesn't allow OpenTofu to detect entirely new
|
||||
objects that might've been created outside of OpenTofu, and so we have a
|
||||
separate "import" workflow to deal with those and that is useful only if
|
||||
the operator already knows that the additional objects have been created.
|
||||
|
||||
This document proposes some changes to OpenTofu's default behavior that should
|
||||
hopefully strike a better compromise where for most operators the refresh
|
||||
behavior will be a benefit rather than a burden. It also proposes retaining
|
||||
something more like the current default behavior as an opt-in, so it will
|
||||
still be available for those who wish to prioritize having a completely-updated
|
||||
state, and those folks can still benefit from some of the performance
|
||||
improvements even when the force full refreshing.
|
||||
|
||||
Related issues:
|
||||
|
||||
- [Option to skip refreshing resource instances whose configuration hasn't changed since the last apply](https://github.com/opentofu/opentofu/issues/1703)
|
||||
- [Make Terraliths a Thing of the Past – Enable Scalable Root Modules in OpenTofu](https://github.com/opentofu/opentofu/issues/2860)
|
||||
- [More granular state storage, locking, and planning](https://github.com/opentofu/opentofu/issues/2662)
|
||||
- [Auto Import Resources If Possible](github.com/opentofu/opentofu/issues/2321)
|
||||
- [Ability to have OpenTofu automatically import an existing object if it exists, or create it otherwise](https://github.com/opentofu/opentofu/issues/1760)
|
||||
|
||||
## Proposed Solution
|
||||
|
||||
There are three main parts to this proposal that could potentially be
|
||||
implemented separately but that are proposed together because the complement
|
||||
each other to produce a better overall system:
|
||||
|
||||
1. Allow providers to optionally optimize their refresh calls by performing
|
||||
many at once in a single request to the remote system, whereever the remote
|
||||
API has support for that.
|
||||
|
||||
This requires a provider protocol extension.
|
||||
|
||||
2. Introduce a new configuration language feature for describing search queries
|
||||
that might discover new remote objects that would be considered to be in
|
||||
the management scope of the current configuration.
|
||||
|
||||
This would extend the meaning of "refresh" to also include discovery of
|
||||
objects that OpenTofu didn't create, after which the operator can decide
|
||||
whether to adopt them into the desired state (by generating configuration)
|
||||
or to delete them as unwanted drift.
|
||||
|
||||
The full functionality of this part of the proposal requires a provider
|
||||
protocol extension, but partial support is possible with existing provider
|
||||
protocol features.
|
||||
|
||||
3. Change OpenTofu's default behavior so that it will only refresh objects whose
|
||||
resource instance configurations have changed since the most recent
|
||||
plan/apply round or which are dependencies of resource instances whose
|
||||
configurations have changed.
|
||||
|
||||
This new compromise gives OpenTofu access to up-to-date information about
|
||||
the objects involved in an intentional configuration change while allowing
|
||||
unrelated objects to remain stale until a future run.
|
||||
|
||||
The current behavior of always refreshing everything would remain available
|
||||
as a new planning option useful for e.g. periodic "drift detection" runs,
|
||||
and OpenTofu would also continue to refresh everything in the `-refresh-only`
|
||||
planning mode where detecting differences is the primary purpose.
|
||||
|
||||
This does not require a provider protocol change, and so would provide
|
||||
immediate benefit regardless of which providers are being used.
|
||||
|
||||
The following subsections describe each of the items above in more detail.
|
||||
|
||||
### Bulk refresh
|
||||
|
||||
Today's OpenTofu calls the provider protocol's "read managed resource" operation
|
||||
separately for each resource instance from the prior state, as part of the
|
||||
process of planning each resource instance.
|
||||
|
||||
|
||||
|
||||
### Automatic discovery of new objects
|
||||
|
||||
### Refreshing only objects whose configuration has changed
|
||||
|
||||
## Open Questions and Alternatives
|
||||
|
||||
### Continue refreshing everything by default?
|
||||
|
||||
This document has proposed that we change the _default_ behavior of OpenTofu
|
||||
so that it will refresh only the subset of objects whose configurations have
|
||||
changed (or that have actions planned for any other reason).
|
||||
|
||||
We could also potentially choose to retain the current default and require
|
||||
those who want the new behavior to explicitly opt in to it.
|
||||
|
||||
The proposal to change the default is founded in the assumption that more
|
||||
operators would want the new behavior than would want to keep the old behavior,
|
||||
that this behavior change is not significant enough to be considered "breaking",
|
||||
and that those who need the previous behavior would be able to add the new
|
||||
planning option relatively easily.
|
||||
|
||||
This echoes a tradeoff made for a similar change made long ago to OpenTofu's
|
||||
predecessor:
|
||||
|
||||
Originally the "apply" command performed the plan and apply phase together
|
||||
immediately without any interactive confirmation prompt, and so anyone who
|
||||
wanted to review their plan before applying it needed to use the saved plan
|
||||
workflow, which is pretty inconvenient for those who are running the program
|
||||
interactively from a shell prompt.
|
||||
|
||||
Someone proposed adding a new option to enable an interactive mode for "apply"
|
||||
which would show the plan and then prompt for confirmation before proceeding.
|
||||
Subsequent discussion found that actually the interactive approval prompt was
|
||||
the more commonly-needed mode, and so the interactive prompt was implemented
|
||||
as the new default behavior and the `-auto-approve` option added for the
|
||||
minority who wanted the previous behavior.
|
||||
|
||||
That appears to have been a good decision in the long run, even though it was
|
||||
admittedly inconvenient for those who needed to adjust their existing usage
|
||||
patterns or wrapper scripts at the time. Similarly, I think that partial
|
||||
refreshing is the better default behavior for most operators, and that the
|
||||
current full-refresh behavior is more suited to special situations like when
|
||||
implementing a "drift detection" system which runs periodically with the
|
||||
explicit goal of finding changes made outside of OpenTofu.
|
||||
Reference in New Issue
Block a user