Commit Graph

190 Commits

Author SHA1 Message Date
James Bardin
ea4cb6a20e check state version during init
The init command needs to parse the state to resolve providers, but
changes to the state format can cause that to fail with difficult to
understand errors. Check the terraform version during init and provide
the same error that would be returned by plan or apply.
2017-12-15 11:17:59 -05:00
James Bardin
ccc9b1d767 replacing orphaned with removed 2017-11-08 22:10:43 -05:00
James Bardin
15ea04af8a remove modules from state
Remove the module entry from the state if a module is no longer in the
configuration. Modules are not removed if there are any existing
resources with the module path as a prefix. The only time this should be
the case is if a module was removed in the config, but the apply didn't
target that module.

Create a NodeModuleRemoved and an associated EvalDeleteModule to track
the module in the graph then remove it from the state. The
NodeModuleRemoved dependencies are simply any other node which contains
the module path as a prefix in its path.

This could have probably been done much easier as a step in pruning the
state, but modules are going to have to be promoted to full graph nodes
anyway in order to support count.
2017-11-08 19:11:53 -05:00
James Bardin
aa2bd0945b properly find orphaned outputs
You can't find orphans by walking the config, because by definition
orphans aren't in the config.

Leaving the broken test for when empty modules are removed from the
state as well.
2017-11-08 14:28:02 -05:00
James Bardin
36b8be43e8 use the new version package
Update all references to the version values to use the new package.
The VersionString function was left in the terraform package
specifically for the aws provider, which is vendored. We can remove that
last call once the provider is updated.
2017-10-19 21:48:08 -04:00
James Bardin
593bf683dc Merge pull request #15448 from hashicorp/jbardin/state-meta-equal
make sure marshaled Meta fields are still equal
2017-08-30 16:00:00 -04:00
Martin Atkins
3a30bfe845 core: evaluate locals and return them for interpolation
We stash the locals in the module state in a map that is ignored for JSON
serialization. We don't include locals in the persisted state because they
can be trivially recomputed and this allows us to assume that they will
pass through verbatim, without any normalization or other transforms
caused by the JSON serialization.

From a user standpoint a local is just a named alias for an expression,
so it's desirable that the result passes through here in as raw a form
as possible, so it behaves as closely as possible to simply using the
given expression directly.
2017-08-21 15:15:25 -07:00
James Bardin
501cbeaffe testState shouldn't rely on mods from WriteState
The state returned from the testState helper shouldn't rely on any
mutations caused by WriteState. The Init function (which is analogous to
NewState) shoudl set any required fields.
2017-07-05 17:47:05 -04:00
Martin Atkins
4d53eaa6df state: more robust handling of state Serial
Previously we relied on a constellation of coincidences for everything to
work out correctly with state serials. In particular, callers needed to
be very careful about mutating states (or not) because many different bits
of code shared pointers to the same objects.

Here we move to a model where all of the state managers always use
distinct instances of state, copied when WriteState is called. This means
that they are truly a snapshot of the state as it was at that call, even
if the caller goes on mutating the state that was passed.

We also adjust the handling of serials so that the state managers ignore
any serials in incoming states and instead just treat each Persist as
the next version after what was most recently Refreshed.

(An exception exists for when nothing has been refreshed, e.g. because
we are writing a state to a location for the first time. In that case
we _do_ trust the caller, since the given state is either a new state
or it's a copy of something we're migrating from elsewhere with its
state and lineage intact.)

The intent here is to allow the rest of Terraform to not worry about
serials and state identity, and instead just treat the state as a mutable
structure. We'll just snapshot it occasionally, when WriteState is called,
and deal with serials _only_ at persist time.

This is intended as a more robust version of #15423, which was a quick
hotfix to an issue that resulted from our previous slopping handling
of state serials but arguably makes the problem worse by depending on
an additional coincidental behavior of the local backend's apply
implementation.
2017-07-05 12:34:30 -07:00
James Bardin
124b80398e make sure marshaled Meta fields are still equal
When the InstanceState.Meta fields are marshaled, numeric values may
change types. The timeout system currently inserts integer values, which
will be unmarshal as float64s.

To ensure that a state which has round-tripped through json is equal to
itself, compare the json representation of the Meta values.
2017-06-30 18:29:42 -04:00
Sander van Harmelen
3d0073e05c core: fix a crash by suggesting a different approach to solve #11170 (#13541)
* Revert #11245, #11321, #11498 and #11757

These PR’s are all related to issue #11170 for which I would like to propose a different solution then the one currently implemented.

* A different approach to solve #11170

This approach has (IMHO) a few advantages with regards to the solution currently implemented. I will elaborate on this in the PR.
2017-04-14 22:32:30 +02:00
James Bardin
928e60672f context Refresh and Apply sometimes return nil
The documentation for Refresh indicates that it will always return a
valid state, but that wasn't true in the case of a graph builder error.
While this same concept wasn't documented for Apply, it was still
assumed in the terraform apply code.

Since the helper testing framework relies on the absence of a state to
determine if it can call Destroy, the Context can't can't start
returning a state in all cases. Document this, and use the State method
to fetch the correct state value after Apply.

Add a nil check to the WriteState function, so that writing a nil state
is a noop.

Make sure to init before sorting the state, to make sure we're not
attempting to sort nil values. This isn't technically needed with the
current code, but it's just safer in general.
2017-04-14 14:56:10 -04:00
James Bardin
b45b6a5c20 remove duplicates in Dependencies
duplicate entries could end up in "depends_on" in the state, which could
possible lead to erroneous state comparisons. Remove them when walking
the graph, and remove existing duplicates when pruning the state.
2017-04-08 15:37:15 -04:00
James Bardin
c55a5082f5 delegate BackendState.Rehash to config.Backend 2017-03-29 18:01:03 -04:00
James Bardin
ff2d753062 add Rehash to terraform.BackendState
This method mirrors that of config.Backend, so we can compare the
configration of a backend read from a config vs that of a backend read
from a state. This will prevent init from reinitializing when using
`-backend-config` options that match the existing state.
2017-03-29 15:53:42 -04:00
Benjamin Boudreau
073fa873ac Fix receive typo (#12881) 2017-03-20 13:15:27 -04:00
James Bardin
41ec5b3bd2 missing defaults in sort
Need to properly catch some sort cases around 0-1 indexing.
This can cause output to shift slightly, resulting in an intermittent
test failure.
2017-02-25 16:50:24 -05:00
James Bardin
82914b5e44 Merge pull request #12219 from hashicorp/jbardin/state-mv-sort
fix sorting of module resources during state mv
2017-02-24 09:49:26 -05:00
James Bardin
43c7bd648c fix sorting of module resources during state mv
Module resource were being sorted lexically by name by the state filter.
If there are 10 or more resources, the order won't match the index
order, and resources will have different indexes in their new location.

Sort the FilterResults by index numerically when the names match.

Clean up the module String output for visual inspection by sorting
Resource name parts numerically when they are an integer value.
2017-02-23 18:27:16 -05:00
Mitchell Hashimoto
41d2c145b2
terraform: State.Equal needs to use reflect for rich types
Due to the change to `interface{}` we need to use `reflect.DeepEqual`
here. With the restriction of primitive types this should always be
safe. We'll never get functions, channels, etc.
2017-02-23 14:00:40 -08:00
Mitchell Hashimoto
3342aa580c
terraform: InstanceState.Meta is value type interface{}
This changes the type of values in Meta for InstanceState to
`interface{}`. They were `string` before.

This will allow richer structures to be persisted to this without
flatmapping them (down with flatmap!). The documentation clearly states
that only primitives/collections are allowed here.

The only thing using this was helper/schema for schema versioning.
Appropriate type checking was added to make this change safe.

The timeout work @catsby is doing will use this for a richer structure.
2017-02-23 10:44:05 -08:00
James Bardin
0c1b138719 Add state locking during backend init
During backend initialization, especially during a migration, there is a
chance that an existing state could be overwritten.

Attempt to get a locks when writing the new state. It would be nice to
always have a lock when reading the states, but the recursive structure
of the Meta.Backend config functions makes that quite complex.
2017-02-09 15:47:27 -05:00
James Bardin
f20485550a Check for no state from the io.Reader
Read state would assume that having a reader meant there should be a
valid state. Check for an empty file and return ErrNoState to
differentiate a bad file from an empty one.
2017-01-30 17:16:57 -05:00
Mitchell Hashimoto
523801dcc2
terraform: support backends in the state 2017-01-26 14:33:49 -08:00
James Bardin
89259a1b00 Fix the removal of empty containers from a flatmap
Removal of empty nested containers from a flatmap would sometimes fail a
sanity check when removed in the wrong order. This would only fail
sometimes due to map iteration. There was also an off-by-one error in
the prefix check which could match the incorrect keys.
2017-01-20 16:23:10 -05:00
James Bardin
2820845f8c Remove 0 counts from flatmap during MergeDiff
When a InstanceState is merged with an InstanceDiff, any maps arrays or
sets that no longer exist are shown as empty with a count of 0. If these
are left in the flatmap structure, they will cause errors during
expansion because their existing in the map affects the counts for
parent structures.
2017-01-17 15:49:50 -05:00
Mitchell Hashimoto
cfb440ea60
terraform: don't prune state on init()
Init should only _add_ values, not remove them.

During graph execution, there are steps that expect that a state isn't
being actively pruned out from under it. Namely: writing deposed states.

Writing deposed states has no way to handle if a state changes
underneath it because the only way to uniquely identify a deposed state
is its index in the deposed array. When destroying deposed resources, we
set the value to `<nil>`. If the array is pruned before the next deposed
destroy, then the indexes have changed, and this can cause a crash.

This PR does the following (with more details below):

  * `init()` no longer prunes.

  * `ReadState()` always prunes before returning. I can't think of a
    scenario where this is unsafe since generally we can always START
    from a pruned state, its just causing problems to prune
    mid-execution.

  * Exported State APIs updated to be robust against nil ModuleStates.

Instead, I think we should adopt the following semantics for init/prune
in our structures that support it (Diff, for example). By having
consistent semantics around these functions, we can avoid this in the
future and have set expectations working with them.

  * `init()` (in anything) will only ever be additive, and won't change
    ordering or existing values. It won't remove values.

  * `prune()` is destructive, expectedly.

  * Functions on a structure must not assume a pruned structure 100% of
    the time. They must be robust to handle nils. This is especially
    important because in many cases values such as `Modules` in state
    are exported so end users can simply modify them outside of the
    exported APIs.

This PR may expose us to unknown crashes but I've tried to cover our
cases in exposed APIs by checking for nil.
2016-12-02 11:48:34 -05:00
James Bardin
a5cb530571 Move the state module cleanup from init to prune
It makes for sense for this to happen in State.prune(). Also move a
redundant pruning from ResourceState.init, and make sure
ResourceState.prune is called from the parent's prune method.
2016-11-20 11:33:41 -05:00
James Bardin
def55e52ca An empty module in state can panic
An empty module, or a module with an empty path can panic during graph
traversal. Make sure we clear these out when reading and writing the
state.
2016-11-18 17:59:07 -05:00
James Nugent
afe2d7b65b Merge pull request #7320 from dtolnay/conflict
core: Allow refresh of local state with no resources
2016-10-14 11:00:46 -05:00
James Bardin
816c04309c Filter nil Deposed values during State init
The Deposed slice wasn't being normalized and nil values could be read
in from a state file. Filter out the nils during init. There is
still a bug in copystructure, but that will be addressed separately.
2016-10-13 13:46:40 -04:00
James Bardin
e5ff4d5bd4 create some unlocked methods for State
State.Init() needs to be called externally, so make sure it only calls
unlocked internal methods once a lock is acquired.
2016-09-16 09:59:04 -04:00
James Bardin
90aab0105d Add locks to InstanceState
Rename receivers for consistency
2016-09-16 09:59:04 -04:00
James Bardin
8d5080fe72 Lock all ResourceState methods
Also rename receivers so they are consistent.
2016-09-16 09:59:04 -04:00
James Bardin
469e71a488 add locks to all exported ModuleState methods 2016-09-16 09:59:04 -04:00
James Bardin
f1b44e36b4 add lock to OutputState.Equal 2016-09-16 09:59:04 -04:00
James Bardin
1235623fad Add locks to exported RemoteState methods 2016-09-16 09:59:04 -04:00
James Bardin
0be90c8994 Add locks to all exported State methods
move implementation into private methods when needed
2016-09-16 09:59:04 -04:00
David Tolnay
61185f083c Merge branch hashicorp/master into dtolnay/conflict 2016-09-07 19:17:22 -07:00
Trevor Pounds
38784cd38f Cleanup inaccurate state structure comments. 2016-09-06 16:24:51 -04:00
Mitchell Hashimoto
3c2db3d572 Merge pull request #8463 from hashicorp/b-read-state-validate
Validate the state on load
2016-08-26 13:27:21 -07:00
James Bardin
4559eec8be Remove the proposed LockedCopy function
We didn't add the LockedCopy function in copystructure, in favor of
using the Config struct directly.
2016-08-25 16:55:28 -04:00
James Bardin
0e6e206465 Add an InstanceState.Set method to set all fields
We con no longer copy an InstanceState via a simple
dereference+assignment because of the mutex which can't be copied. This
adds a set method to properly set all field from another InstanceState,
and take the appropriate locks while doing so.
2016-08-25 14:41:51 -04:00
James Bardin
7a579c271d Remove GoString methods from state
These method set the GoString format behavior, but they only output the
default GoString format. Remove them to prevent copying mutex values.
2016-08-25 14:41:39 -04:00
Mitchell Hashimoto
73f7c04159
terraform: clear docs for devs 2016-08-24 18:44:54 -07:00
Mitchell Hashimoto
3376611ad0
terraform: Validate validates single module states 2016-08-24 18:42:13 -07:00
Mitchell Hashimoto
c65bbc4f0c
terraform: minor edits to reading state to prep for validation 2016-08-24 18:20:47 -07:00
James Bardin
056fd70da4 Add locks to state structs for copying
Add locks to the state structs to handle concurrency during the graph
walks. We can't embed the mutexes due to serialization constraints when
communicating with providers, so expose the Lock/Unlock methods
manually.

Use copystructure.LockedCopy to ensure locks are honored.
2016-08-24 11:15:52 -04:00
Mitchell Hashimoto
a44c8b8760
terraform: state mv tests 2016-08-18 15:05:42 -04:00
James Bardin
cdb80f68a8 Ensure better state normalization
Fix checksum issue with remote state

If we read a state file with "null" objects in a module and they become
initialized to an empty map the state file may be written out with empty
objects rather than "null", changing the checksum. If we can detect
this, increment the serial number to prevent a conflict in atlas.

Our fakeAtlas test server now needs to decode the state directly rather
than using the ReadState function, so as to be able to read the state
unaltered.

The terraform.State data structures have initialization spread out
throughout the package. More thoroughly initialize State during
ReadState, and add a call to init() during WriteState as another
normalization safeguard.

Expose State.init through an exported Init() method, so that a new State
can be completely realized outside of the terraform package.
Additionally, the internal init now completely walks all internal state
structures ensuring that all maps and slices are initialized.  While it
was mentioned before that the `init()` methods are problematic with too
many call sites, expanding this out better exposes the entry points that
will need to be refactored later for improved concurrency handling.

The State structures had a mix of `omitempty` fields. Remove omitempty
for all maps and slices as part of this normalization process. Make
Lineage mandatory, which is now explicitly set in some tests.
2016-08-12 11:09:50 -04:00