Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix panic from a null resources module in a state file #8120

Merged
merged 1 commit into from
Aug 16, 2016

Conversation

jbardin
Copy link
Member

@jbardin jbardin commented Aug 10, 2016

https://gist.github.com/davidneudorfer/39bfdd1854384e57537fc0a5e3a4fc65

Make sure all maps and slices are initialized when reading a state file to prevent nil panics like above.

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.

@jbardin jbardin added the core label Aug 10, 2016
@jbardin jbardin changed the title Fix panic from a null resources module in a state file WIP: Fix panic from a null resources module in a state file Aug 10, 2016
@jbardin jbardin force-pushed the jbardin/null-state-module branch 4 times, most recently from af4be59 to 2e69ec5 Compare August 11, 2016 14:45
@jbardin jbardin changed the title WIP: Fix panic from a null resources module in a state file Fix panic from a null resources module in a state file Aug 11, 2016
@jbardin jbardin force-pushed the jbardin/null-state-module branch 6 times, most recently from f955f98 to 4d55eab Compare August 12, 2016 15:04
@jbardin
Copy link
Member Author

jbardin commented Aug 12, 2016

I ended up squashing all the commits down here, since the there were too many change done and undone by the series of commits. This commit is a little large, but much easier to understand in isolation.

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.
@jbardin
Copy link
Member Author

jbardin commented Aug 12, 2016

cc @phinze and/or @jen20 for review

@@ -713,7 +752,7 @@ type ModuleState struct {
// Terraform. If Terraform doesn't find a matching ID in the
// overall state, then it assumes it isn't managed and doesn't
// worry about it.
Dependencies []string `json:"depends_on,omitempty"`
Dependencies []string `json:"depends_on"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The normalization-serial-bump below will also cover these changes as well, yes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, since every ReadState checks WriteState for changes, we'll always bump the serial on a change.

@phinze
Copy link
Contributor

phinze commented Aug 12, 2016

Looking good on first pass!

Trying to structure a "rule of thumb" going forward: never create a terraform.State, ResourceState, or InstanceState without Init(). Does that sound right?

@jbardin
Copy link
Member Author

jbardin commented Aug 12, 2016

I don't want to commit yet to a global pattern for handling these, as I'd rather not have this api cruft leak out into provider-land.

Right now it should be the case that init() is called everywhere it matters, and you only need to call it manually for changes within the terraform package or tests that build their own state. I was going to do further review when I get back, as the init() calls all over place are part of the concurrency issues we have, and need to be cleaned up. It's going to take a little planning to not have this affect providers.

@phinze
Copy link
Contributor

phinze commented Aug 12, 2016

Cool that all makes sense. This LGTM, but let's also get @jen20 to do a triple check here before merge.

@phinze phinze self-assigned this Aug 15, 2016
@phinze
Copy link
Contributor

phinze commented Aug 15, 2016

cc @jen20 or @mitchellh for double check review then I'll merge it 👍

@mitchellh
Copy link
Contributor

LGTM.

One thing we should probably look into in the future is exposing test helpers via testing.go or testing_state.go (our convention is just prefixing the file with testing) for public APIs to get variously formed state files that can be used in and out of the core package that handles this in various ways.

I see there are a lot of ways that that wouldn't have helped but at least for "I need a ready to go state" those cases should ideally be centralized in a single function.

This PR LGTM though!

@@ -742,6 +743,20 @@ func TestRefresh_displaysOutputs(t *testing.T) {
}
}

// When creating an InstaneState for direct comparison to one contained in
// terraform.State, all fields must be inintialized (duplicating the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small typo here: initialized, awesome work otherwise! :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Will fix on master.

@phinze phinze merged commit 50df583 into master Aug 16, 2016
@phinze phinze deleted the jbardin/null-state-module branch August 16, 2016 14:45
@ghost
Copy link

ghost commented Apr 23, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Apr 23, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants