Merge pull request #15566 from hashicorp/jbardin/state-serial
Add warning to mismatched plan state
This commit is contained in:
commit
9a7ffbfb1b
|
@ -49,6 +49,10 @@ func (b *Local) context(op *backend.Operation) (*terraform.Context, state.State,
|
|||
}
|
||||
|
||||
// Load our state
|
||||
// By the time we get here, the backend creation code in "command" took
|
||||
// care of making s.State() return a state compatible with our plan,
|
||||
// if any, so we can safely pass this value in both the plan context
|
||||
// and new context cases below.
|
||||
opts.State = s.State()
|
||||
|
||||
// Build the context
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/terraform/config/module"
|
||||
|
@ -43,7 +44,11 @@ type Plan struct {
|
|||
// Context returns a Context with the data encapsulated in this plan.
|
||||
//
|
||||
// The following fields in opts are overridden by the plan: Config,
|
||||
// Diff, State, Variables.
|
||||
// Diff, Variables.
|
||||
//
|
||||
// If State is not provided, it is set from the plan. If it _is_ provided,
|
||||
// it must be Equal to the state stored in plan, but may have a newer
|
||||
// serial.
|
||||
func (p *Plan) Context(opts *ContextOpts) (*Context, error) {
|
||||
var err error
|
||||
opts, err = p.contextOpts(opts)
|
||||
|
@ -60,11 +65,23 @@ func (p *Plan) contextOpts(base *ContextOpts) (*ContextOpts, error) {
|
|||
|
||||
opts.Diff = p.Diff
|
||||
opts.Module = p.Module
|
||||
opts.State = p.State
|
||||
opts.Targets = p.Targets
|
||||
|
||||
opts.ProviderSHA256s = p.ProviderSHA256s
|
||||
|
||||
if opts.State == nil {
|
||||
opts.State = p.State
|
||||
} else if !opts.State.Equal(p.State) {
|
||||
// Even if we're overriding the state, it should be logically equal
|
||||
// to what's in plan. The only valid change to have made by the time
|
||||
// we get here is to have incremented the serial.
|
||||
//
|
||||
// Due to the fact that serialization may change the representation of
|
||||
// the state, there is little chance that these aren't actually equal.
|
||||
// Log the error condition for reference, but continue with the state
|
||||
// we have.
|
||||
log.Println("[WARNING] Plan state and ContextOpts state are not equal")
|
||||
}
|
||||
|
||||
thisVersion := VersionString()
|
||||
if p.TerraformVersion != "" && p.TerraformVersion != thisVersion {
|
||||
return nil, fmt.Errorf(
|
||||
|
|
|
@ -118,3 +118,52 @@ func TestReadWritePlan(t *testing.T) {
|
|||
t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actualStr, expectedStr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanContextOptsOverrideStateGood(t *testing.T) {
|
||||
plan := &Plan{
|
||||
Diff: &Diff{
|
||||
Modules: []*ModuleDiff{
|
||||
{
|
||||
Path: []string{"test"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Module: module.NewTree("test", nil),
|
||||
State: &State{
|
||||
TFVersion: "sigil",
|
||||
Serial: 1,
|
||||
},
|
||||
Vars: map[string]interface{}{"foo": "bar"},
|
||||
Targets: []string{"baz"},
|
||||
|
||||
TerraformVersion: VersionString(),
|
||||
ProviderSHA256s: map[string][]byte{
|
||||
"test": []byte("placeholder"),
|
||||
},
|
||||
}
|
||||
|
||||
base := &ContextOpts{
|
||||
State: &State{
|
||||
TFVersion: "sigil",
|
||||
Serial: 2,
|
||||
},
|
||||
}
|
||||
|
||||
got, err := plan.contextOpts(base)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating context: %s", err)
|
||||
}
|
||||
|
||||
want := &ContextOpts{
|
||||
Diff: plan.Diff,
|
||||
Module: plan.Module,
|
||||
State: base.State,
|
||||
Variables: plan.Vars,
|
||||
Targets: plan.Targets,
|
||||
ProviderSHA256s: plan.ProviderSHA256s,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue