Commit Graph

110 Commits

Author SHA1 Message Date
Alex Pilon
4bf43efcfd
move hcl2shim package to configs 2019-08-06 19:58:58 -04:00
Alex Pilon
7f8f198719
remove UnknownVariabeValue from config and update references to shim 2019-07-17 22:41:24 -04:00
Martin Atkins
861a2ebf26 helper/schema: Use a more targeted shim for nested set diff applying
We previously attempted to make the special diff apply behavior for nested
sets of objects work with attribute mode by totally discarding attribute
mode for all shims.

In practice, that is too broad a solution: there are lots of other shimming
behaviors that we _don't_ want when attribute mode is enabled. In
particular, we need to make sure that the difference between null and
empty can be seen in configuration.

As a compromise then, we will give all of the shims access to the real
ConfigMode and then do a more specialized fixup within the diff-apply
logic: we'll construct a synthetic nested block schema and then use that
to run our existing logic to deal with nested sets of objects, while
using the previous behavior in all other cases.

In effect, this means that the special new behavior only applies when the
provider uses the opt-in ConfigMode setting on a particular attribute,
and thus this change has much less risk of causing broad, unintended
regressions elsewhere.
2019-04-17 07:47:31 -07:00
James Bardin
6868ddd085 don't set NewRemoved values as empty strings
NewRemoved diff values were somtimes left in maps and lists.
2019-03-29 13:56:43 -04:00
James Bardin
892674a3f9 don't recalculate existing block counts in diff
If a block is uneffected by diffs, keep the block count value regardless
of what it is. Blocks containing zero values will often be represented
by only the count value.
2019-03-12 12:04:35 -04:00
James Bardin
da389d6cd4 simple list diffs may also have missing elements
Like was done for list blocks, simple lists of strings may be missing
empty string elements, and any list may be implicitly truncated.
2019-02-14 13:06:04 -05:00
James Bardin
c34c37fbd5 missed .% suffixes in diff.Apply
Diff.Apply checks for unneeded container count diffs, but was missing
the check for maps.

Add an early return for planning a destroy.
2019-02-13 19:09:46 -05:00
James Bardin
1ca7531cc7 allow implicit empty strings in lists
The helper/schema handling of lists loses empty string values, but
retains the correct count. Only re-count the values if the count is
missing entirely, and allow our shims to re-populate the zero values.
2019-02-11 19:24:14 -05:00
James Bardin
411df99f33 only force top-level id's back to unknown
Nested structures may have "id" fields, which should be treated
normally.
2019-02-05 16:16:08 -05:00
James Bardin
6f7e1ff8eb more precise handling of removed list elements
When elements are removed from a list, all attributes may not be present
in the diff. Once the individual attributes diffs are applied, use the
length to truncate the flatmapped list to the correct length.
2019-01-30 14:55:04 -05:00
James Bardin
7dd0acc46b don't count empty containers in diff.Apply
If there were no matching keys, and there was no diff at all, don't set
a zero count for the container. Normally Providers can't reliably detect
empty vs unset here, but there are some cases that worked.
2019-01-23 19:34:11 -05:00
James Bardin
9b30da500d missing prefix in recounted map
Missing prefix in map recount. This generally passes tests since the
actual count should already be there and be correct, then ethe extra key
is ignored by the shims.
2019-01-23 14:57:04 -05:00
James Bardin
273f20ec8b update comment and fix core test
One terraform test was broken when the result became more correct.
2019-01-22 18:38:17 -05:00
James Bardin
7257258f18 new Diff.Apply
The previous version assumed the diff could be applied verbatim, and
only used the schema at the top level since diffs are "flat". This
turned out to not work reliably with nested blocks. The new Apply method
is driven completely by the schema, and handles nested blocks separately
from other collections.
2019-01-22 18:10:12 -05:00
James Bardin
0b7be2d0e3 fixes for the remaining tests
It's possible that a computed collection could be handled by the
attribute name, rather than the index count value.

Use a new testDiffFn for some tests, which don't work with the old
function that can't determine `computed` without the schema.
2018-11-19 18:56:50 -05:00
James Bardin
e4270993be remove unused value 2018-11-16 15:28:30 -05:00
James Bardin
db968733da re-count the flatmapped containers
When applying a legacy diff, recount the flatmapped containers. We can't
trust helper/schema to return the correct value, if it even exists.
2018-11-16 15:26:16 -05:00
James Bardin
89b2c6f21e comment fixes 2018-11-16 11:24:14 -05:00
James Bardin
16f28f7348 new mechanism for applying a diff to a value
This attempts to apply the diff in order to get consistent output from
the shimmed values.
2018-11-16 09:59:03 -05:00
James Bardin
b872491baa incremental progress towards applying diffs 2018-11-16 09:58:42 -05:00
James Bardin
7e4f09c787 don't apply unchanged attributes from legacy diffs
If a legacy diff has equal old and new values, don't apply the diff.
These would show up in sets, because of the overall change in set key.
2018-11-01 16:19:17 -04:00
Martin Atkins
cf903b9bec core: testDiffFn must populate old value for "type"
Previously testDiffFn was just assuming that the prior value for "type"
was always the empty string, but that doesn't hold if a mocked object is
updated in-place with a previously-populated value for type.

This wasn't a problem before because the old values in the diff were
largely just for presentation to the user, but we do now verify that the
old values match what we're applying to as an extra safety check and so
we must populate the old value properly.

This fix is verified by TestContext2Apply_Provisioner_Diff.
2018-10-16 19:14:11 -07:00
Martin Atkins
e488ff126e core: InstanceDiff.ApplyToValue correctly handle creates
We previously tried to take a shortcut for an empty diff, just returning
the given value directly. This is incorrect in the weird case where we're
creating a new instance but it has no attributes (and thus an empty diff)
because in that case we'd return the given null value, turning the result
into a no-op or destroy change.

To fix this, we just always do the work to construct a new value, even
if we might end up doing all this just to reconstruct the same value we
started with in some cases.
2018-10-16 19:14:11 -07:00
Martin Atkins
76d11f44cc core: Move some of the helper/schema shims so provider mock can use them
The old names are now wrappers around these new functions.
2018-10-16 19:14:11 -07:00
Martin Atkins
eb54715902 core: fix string rendering of modules in diffs
This was assuming our old practice of a slice starting with the string
"root". We'll normalize here and then stringify the result to ensure that
we get a string consistent with what's used elsewhere.

This is primarily aimed at fixing some of the context plan tests.
2018-10-16 18:48:28 -07:00
Martin Atkins
c937c06a03 terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.

The three main goals here are:
- Use the configuration models from the "configs" package instead of the
  older models in the "config" package, which is now deprecated and
  preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
  new "lang" package, instead of the Interpolator type and related
  functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
  rather than hand-constructed strings. This is not critical to support
  the above, but was a big help during the implementation of these other
  points since it made it much more explicit what kind of address is
  expected in each context.

Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.

I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-10-16 18:46:46 -07:00
James Bardin
8d1e479fc7 don't ignore partial containers in diffs
Containers (maps, lists, sets) in an InstanceDiff need to be handled in
their entirety.  Unchanged values cannot be filtered out from diffs, as
providers expect attribute containers to be complete.

If a value in ignore_changes maps to a single key in an attribute
container, and there are other changes present, that ignored value must
be included in the diff as well.
2018-01-17 19:13:32 -05:00
Nathan Evans
45439d0ac3 Add inequality check to ignore redundant diff attributes 2017-11-28 10:11:19 -07:00
Martin Atkins
c003e8f9a6 core: don't compare attribute values in Diff.Same
We previously didn't compare values but had a TODO to start doing so,
which we then recently did. Unfortunately it turns out that we _depend_
on not comparing values here, because when we use EvalCompareDiff (a key
user of Diff.Same) we pass in a diff made from a fresh re-interpolation
of the configuration and so any non-pure function results (timestamp,
uuid) have produced different values.
2017-11-03 16:11:13 -07:00
Chris Marchesi
5031767b93 terraform: Add more exception cases for value comparison
Needed to add more cases to support value comparison exceptions that the
rest of TF expects to work (this fixes tests in various places).

Also moved things to a switch block so that it's a little more compact.
2017-11-01 14:25:32 -07:00
Chris Marchesi
12378b4ee2 terraform: Add value check to diff.Same
A diff new needs to pass basic value checks to be considered the
"same". Several provisions have been added to ensure that the list, set,
and RequiresNew behaviours that have needed some exceptions in the past
are preserved in this new logic.

This ensures that we are checking for value equality as much as
possible, which will be more important when we transition to the
possibility of diffs being sourced from external data.
2017-11-01 14:25:32 -07:00
Martin Atkins
3ea159297c command/format: improve consistency of plan results
Previously the rendered plan output was constructed directly from the
core plan and then annotated with counts derived from the count hook.
At various places we applied little adjustments to deal with the fact that
the user-facing diff model is not identical to the internal diff model,
including the special handling of data source reads and destroys. Since
this logic was just muddled into the rendering code, it behaved
inconsistently with the tally of adds, updates and deletes.

This change reworks the plan formatter so that it happens in two stages:
- First, we produce a specialized Plan object that is tailored for use
  in the UI. This applies all the relevant logic to transform the
  physical model into the user model.
- Second, we do a straightforward visual rendering of the display-oriented
  plan object.

For the moment this is slightly overkill since there's only one rendering
path, but it does give us the benefit of letting the counts be derived
from the same data as the full detailed diff, ensuring that they'll stay
consistent.

Later we may choose to have other UIs for plans, such as a
machine-readable output intended to drive a web UI. In that case, we'd
want the web UI to consume a serialization of the _display-oriented_ plan
so that it doesn't need to re-implement all of these UI special cases.

This introduces to core a new diff action type for "refresh". Currently
this is used _only_ in the UI layer, to represent data source reads.
Later it would be good to use this type for the core diff as well, to
improve consistency, but that is left for another day to keep this change
focused on the UI.
2017-09-01 17:55:05 -07:00
Rob Phoenix
de2927d0b4 core: fix some typos in comments 2017-06-22 07:09:07 -07:00
James Bardin
0ae0076e3a Correctly filter flatmapped values in diff
When transforming a diff from DestroyCreate to a simple Update,
ignore_changes can cause keys from flatmapped objects to be filtered
form the diff. We need to filter each flatmapped container as a whole to
ensure that unchanged keys aren't lost in the update.
2017-03-21 09:11:54 -04:00
Mitchell Hashimoto
fe32f7b189
terraform: ignore RequiresNew for collection removal in diff.Same
Fixes #11349

I tracked this bug back to the early 0.7 days so this has been around a
really long time. I wanted to confirm that this wasn't introduced by any
new graph changes and it appears to predate all of that. I couldn't find
a single 0.7.x release where this worked, and I didn't want to go back
to 0.6.x since it was pre-vendoring.

The test case shows the logic the best, but the basic idea is: for
collections that go to zero elements, the "RequiresNew" sameness check
should be ignored, since the new diff can choose to not have that at all
in the diff.
2017-02-06 17:46:48 -08:00
Mitchell Hashimoto
068b2b2dec
terraform: add Meta field to diffs
This adds a Meta field (similar to InstanceState.Meta) to InstanceDiff.

This allows providers to store arbitrary k/v data as part of a diff and
have it persist through to the Apply. This will be used by helper/schema
for timeout storage being done by @catsby.

The type here is `map[string]interface{}`. A couple notes:

  * **Not using `string`**: The Meta field of InstanceState is a string
    value. We've learned that forcing things to strings is bad. Let's
    just allow types.

  * **Primitives only**: Even though it is type `interface{}`, it must
    be able to cleanly pass the go-plugin RPC barrier as well as be
    encoded to a file as Gob. Given these constraints, the value must
    only comprise of primitive types and collections. No structs,
    functions, channels, etc.
2017-01-31 11:50:37 -08:00
Mitchell Hashimoto
80457b689c
terraform: do the deposed check within EvalDiff
There is never any reason to separate the two.
2016-11-28 14:34:24 -08:00
Mitchell Hashimoto
6ee3a08799
terraform: deposed shows up in plan, tests 2016-11-28 14:32:42 -08:00
Mitchell Hashimoto
55ef93f0f9
terraform: Diff.Same should understand that Destroy might go false 2016-11-15 11:26:42 -08:00
Mitchell Hashimoto
f9fee4106f
terraform: Diff.Prune 2016-11-08 13:28:50 -08:00
James Bardin
797a1b339d DebugInfo and DebugGraph
Implement debugInfo and the DebugGraph

DebugInfo will be a global variable through which graph debug
information can we written to a compressed archive. The DebugInfo
methods are all safe for concurrent use, and noop with a nil receiver.
The API outside of the terraform package will be to call SetDebugInfo
to create the archive, and CloseDebugInfo() to properly close the file.
Each write to the archive will be flushed and sync'ed individually, so
in the event of a crash or a missing call to Close, the archive can
still be recovered.

The DebugGraph is a representation of a terraform Graph to be written to
the debug archive, currently in dot format. The DebugGraph also contains
an internal buffer with Printf and Write methods to add to this buffer.
The buffer will be written to an accompanying file in the debug archive
along with the graph.

This also adds a GraphNodeDebugger interface. Any node implementing
`NodeDebug() string` can output information to annotate the debug graph
node, and add the data to the log. This interface may change or be
removed to provide richer options for debugging graph nodes.

The new graph builders all delegate the build to the BasicGraphBuilder.
Having a Name field lets us differentiate the actual builder
implementation in the debug graphs.
2016-11-04 11:30:51 -04:00
Mitchell Hashimoto
df981b234d
terraform: NewComputed doesn't quit Same logic
For #9618, we added the ability to ignore old diffs that were computed
and removed (because the ultimate value ended up being the same). This
ended up breaking computed list/set logic.

The correct behavior, as is evident by how the other "skip" logics work,
is to set `ok = true` so that the remainder of the logic can run which
handles stuff such as computed lists and sets.
2016-11-01 09:53:53 -07:00
Mitchell Hashimoto
3f36787207 Merge pull request #9618 from hashicorp/b-computed-prim
helper/schema,terraform: handle computed primitives in diffs
2016-10-28 10:44:13 -04:00
Mitchell Hashimoto
95d37ea79c
helper/schema,terraform: handle computed primtives in diffs
Fixes #3309

There are two primary changes, one to how helper/schema creates diffs
and one to how Terraform compares diffs. Both require careful
understanding.

== 1. helper/schema Changes

helper/schema, given any primitive field (string, int, bool, etc.)
_used to_ create a basic diff when given a computed new value (i.e. from
an unkown interpolation). This would put in the plan that the old value
is whatever the old value was, and the new value was the actual
interpolation. For example, from #3309, the diff showed the following:

```
~ module.test.aws_eip.test-instance.0
    instance: "<INSTANCE ID>" => "${element(aws_instance.test-instance.*.id, count.index)}"
```

Then, when running `apply`, the diff would be realized and you would get
a diff mismatch error because it would realize the final value is the
same and remove it from the diff.

**The change:** `helper/schema` now marks unknown primitive values with
`NewComputed` set to true. Semantically this is correct for the diff to
have this information.

== 2. Terraform Diff.Same Changes

Next, the way Terraform compares diffs needed to be updated

Specifically, the case where the diff from the plan had a NewComputed
primitive and the diff from the apply _no longer has that value_. This
is possible if the computed value ended up being the same as the old
value. This is allowed to pass through.

Together, these fix #3309.
2016-10-25 22:36:59 -04:00
Mitchell Hashimoto
ac9a049d19
terraform: Diff.Equal ignores ModuleDiff.Destroy
This is necessary to get the shadow working properly with the destroy
graph since the destroy graph doesn't set this field but the end state
is still the same.
2016-10-22 12:12:30 -07:00
Mitchell Hashimoto
ceb613d449
terraform: don't set destroy module on diff
This is something that should be determined and done during an apply. It
doesn't make a lot of sense that the plan is doing it (in its current
form at least).
2016-10-22 12:12:30 -07:00
Mitchell Hashimoto
50afee2a30
terraform: Diff.Empty should be true for nil Diff 2016-10-19 13:38:01 -07:00
Mitchell Hashimoto
35d1868618
terraform: remove ModuleDiff.GoString
To address comments by @jbardin re: if we had a mutex this will fail
vet.
2016-10-19 10:07:47 -07:00
Mitchell Hashimoto
98fa7d92a4
terraform: support data source apply for shadows 2016-10-12 18:56:57 +08:00
Mitchell Hashimoto
31f8d13678
terraform: Diff.Equal and tests 2016-10-11 22:17:31 +08:00