terraform: run the shadow graph for Apply operations (everything fails)

This commit is contained in:
Mitchell Hashimoto 2016-10-03 09:45:18 -07:00
parent 02e93f5920
commit 742af8752b
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
3 changed files with 36 additions and 9 deletions

View File

@ -375,7 +375,7 @@ func (c *Context) Apply() (*State, error) {
if c.destroy { if c.destroy {
walker, err = c.walk(graph, nil, walkDestroy) walker, err = c.walk(graph, nil, walkDestroy)
} else { } else {
walker, err = c.walk(graph, nil, walkApply) walker, err = c.walk(graph, graph, walkApply)
} }
if len(walker.ValidationErrors) > 0 { if len(walker.ValidationErrors) > 0 {
@ -641,6 +641,7 @@ func (c *Context) walk(
// on the real walk so it is fine to start first. // on the real walk so it is fine to start first.
shadowCh = make(chan error) shadowCh = make(chan error)
go func() { go func() {
log.Printf("[INFO] Starting shadow graph walk: %s", operation.String())
shadowCh <- shadow.Walk(shadowWalker) shadowCh <- shadow.Walk(shadowWalker)
}() }()
} }
@ -660,14 +661,21 @@ func (c *Context) walk(
} }
// Wait for the walk to end // Wait for the walk to end
log.Printf("[DEBUG] Waiting for shadow graph to complete...")
if err := <-shadowCh; err != nil { if err := <-shadowCh; err != nil {
c.shadowErr = multierror.Append(c.shadowErr, err) c.shadowErr = multierror.Append(c.shadowErr, err)
} }
// If we're supposed to fail on shadow errors, then report it if c.shadowErr == nil {
if contextFailOnShadowError && c.shadowErr != nil { log.Printf("[INFO] Shadow graph success!")
realErr = multierror.Append(realErr, multierror.Prefix( } else {
c.shadowErr, "shadow graph:")) log.Printf("[ERROR] Shadow graph error: %s", c.shadowErr)
// If we're supposed to fail on shadow errors, then report it
if contextFailOnShadowError {
realErr = multierror.Append(realErr, multierror.Prefix(
c.shadowErr, "shadow graph:"))
}
} }
} }

View File

@ -14,7 +14,7 @@ import (
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
) )
func TestContext2Apply(t *testing.T) { func TestContext2Apply_basic(t *testing.T) {
m := testModule(t, "apply-good") m := testModule(t, "apply-good")
p := testProvider("aws") p := testProvider("aws")
p.ApplyFn = testApplyFn p.ApplyFn = testApplyFn

View File

@ -19,13 +19,13 @@ import (
// copied, no real providers or resources are used, etc. // copied, no real providers or resources are used, etc.
func newShadowContext(c *Context) (*Context, *Context, io.Closer) { func newShadowContext(c *Context) (*Context, *Context, io.Closer) {
// Copy the targets // Copy the targets
targetRaw, err := copystructure.Config{Lock: true}.Copy(c.targets) targetRaw, err := copystructure.Copy(c.targets)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// Copy the variables // Copy the variables
varRaw, err := copystructure.Config{Lock: true}.Copy(c.variables) varRaw, err := copystructure.Copy(c.variables)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -45,6 +45,12 @@ func newShadowContext(c *Context) (*Context, *Context, io.Closer) {
targets: targetRaw.([]string), targets: targetRaw.([]string),
uiInput: nil, // TODO uiInput: nil, // TODO
variables: varRaw.(map[string]interface{}), variables: varRaw.(map[string]interface{}),
// Hardcoded to 4 since parallelism in the shadow doesn't matter
// a ton since we're doing far less compared to the real side
// and our operations are MUCH faster.
parallelSem: NewSemaphore(4),
providerInputConfig: make(map[string]map[string]interface{}),
} }
// Create the real context. This is effectively just a copy of // Create the real context. This is effectively just a copy of
@ -53,5 +59,18 @@ func newShadowContext(c *Context) (*Context, *Context, io.Closer) {
real := *c real := *c
real.providers = providerFactory.RealMap() real.providers = providerFactory.RealMap()
return &real, shadow, nil return &real, shadow, &shadowContextCloser{
Providers: providerFactory,
}
}
// shadowContextCloser is the io.Closer returned by newShadowContext that
// closes all the shadows and returns the results.
type shadowContextCloser struct {
Providers interface{}
}
// Close closes the shadow context.
func (c *shadowContextCloser) Close() error {
return nil
} }