Merge pull request #26738 from hashicorp/jbardin/eval-diagnostics
Eval diagnostics
This commit is contained in:
commit
d1ac382ec9
|
@ -924,7 +924,7 @@ func TestApply_shutdown(t *testing.T) {
|
|||
"-auto-approve",
|
||||
testFixturePath("apply-shutdown"),
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
if code := c.Run(args); code != 1 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
|
|
|
@ -845,12 +845,8 @@ func TestPlan_shutdown(t *testing.T) {
|
|||
"-state=nonexistent.tfstate",
|
||||
testFixturePath("apply-shutdown"),
|
||||
})
|
||||
if code != 0 {
|
||||
// FIXME: In retrospect cancellation ought to be an unsuccessful exit
|
||||
// case, but we need to do that cautiously in case it impacts automation
|
||||
// wrappers. See the note about this in the terraform.stopHook
|
||||
// implementation for more.
|
||||
t.Errorf("wrong exit code %d; want 0\noutput:\n%s", code, ui.OutputWriter.String())
|
||||
if code != 1 {
|
||||
t.Errorf("wrong exit code %d; want 1\noutput:\n%s", code, ui.OutputWriter.String())
|
||||
}
|
||||
|
||||
select {
|
||||
|
|
|
@ -1734,8 +1734,16 @@ func TestContext2Apply_cancel(t *testing.T) {
|
|||
}()
|
||||
|
||||
state := <-stateCh
|
||||
if applyDiags.HasErrors() {
|
||||
t.Fatalf("unexpected errors: %s", applyDiags.Err())
|
||||
// only expecting an early exit error
|
||||
if !applyDiags.HasErrors() {
|
||||
t.Fatal("expected early exit error")
|
||||
}
|
||||
|
||||
for _, d := range applyDiags {
|
||||
desc := d.Description()
|
||||
if desc.Summary != "execution halted" {
|
||||
t.Fatalf("unexpected error: %v", applyDiags.Err())
|
||||
}
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(state.String())
|
||||
|
@ -1812,8 +1820,16 @@ func TestContext2Apply_cancelBlock(t *testing.T) {
|
|||
|
||||
// Wait for apply to complete
|
||||
state := <-stateCh
|
||||
if applyDiags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", applyDiags.Err())
|
||||
// only expecting an early exit error
|
||||
if !applyDiags.HasErrors() {
|
||||
t.Fatal("expected early exit error")
|
||||
}
|
||||
|
||||
for _, d := range applyDiags {
|
||||
desc := d.Description()
|
||||
if desc.Summary != "execution halted" {
|
||||
t.Fatalf("unexpected error: %v", applyDiags.Err())
|
||||
}
|
||||
}
|
||||
|
||||
checkStateString(t, state, `
|
||||
|
@ -1882,7 +1898,18 @@ func TestContext2Apply_cancelProvisioner(t *testing.T) {
|
|||
|
||||
// Wait for completion
|
||||
state := <-stateCh
|
||||
assertNoErrors(t, applyDiags)
|
||||
|
||||
// we are expecting only an early exit error
|
||||
if !applyDiags.HasErrors() {
|
||||
t.Fatal("expected early exit error")
|
||||
}
|
||||
|
||||
for _, d := range applyDiags {
|
||||
desc := d.Description()
|
||||
if desc.Summary != "execution halted" {
|
||||
t.Fatalf("unexpected error: %v", applyDiags.Err())
|
||||
}
|
||||
}
|
||||
|
||||
checkStateString(t, state, `
|
||||
aws_instance.foo: (tainted)
|
||||
|
@ -12250,3 +12277,52 @@ resource "test_resource" "foo" {
|
|||
t.Fatal("missing 'test_resource.foo' in state:", state)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Apply_rpcDiagnostics(t *testing.T) {
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
resource "test_instance" "a" {
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
p := testProvider("test")
|
||||
p.PlanResourceChangeFn = testDiffFn
|
||||
p.ApplyResourceChangeFn = testApplyFn
|
||||
p.GetSchemaReturn = &ProviderSchema{
|
||||
ResourceTypes: map[string]*configschema.Block{
|
||||
"test_instance": {
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Computed: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p.ValidateResourceTypeConfigResponse = providers.ValidateResourceTypeConfigResponse{
|
||||
Diagnostics: tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("don't frobble")),
|
||||
}
|
||||
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Config: m,
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
_, diags := ctx.Plan()
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
}
|
||||
|
||||
_, diags = ctx.Apply()
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
}
|
||||
|
||||
for _, d := range diags {
|
||||
des := d.Description().Summary
|
||||
if !strings.Contains(des, "frobble") {
|
||||
t.Fatalf(`expected frobble, got %q`, des)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6421,3 +6421,46 @@ data "test_data_source" "b" {
|
|||
t.Fatal("data source b was not read during plan")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Plan_rpcDiagnostics(t *testing.T) {
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
resource "test_instance" "a" {
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
p := testProvider("test")
|
||||
p.PlanResourceChangeFn = testDiffFn
|
||||
p.GetSchemaReturn = &ProviderSchema{
|
||||
ResourceTypes: map[string]*configschema.Block{
|
||||
"test_instance": {
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Computed: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p.ValidateResourceTypeConfigResponse = providers.ValidateResourceTypeConfigResponse{
|
||||
Diagnostics: tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("don't herd cats")),
|
||||
}
|
||||
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Config: m,
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
_, diags := ctx.Plan()
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
}
|
||||
|
||||
for _, d := range diags {
|
||||
des := d.Description().Summary
|
||||
if !strings.Contains(des, "cats") {
|
||||
t.Fatalf(`expected cats, got %q`, des)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1795,3 +1795,46 @@ resource "test_instance" "a" {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Validate_rpcDiagnostics(t *testing.T) {
|
||||
// validate module and output depends_on
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
resource "test_instance" "a" {
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
p := testProvider("test")
|
||||
p.GetSchemaReturn = &ProviderSchema{
|
||||
ResourceTypes: map[string]*configschema.Block{
|
||||
"test_instance": {
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Computed: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p.ValidateResourceTypeConfigResponse = providers.ValidateResourceTypeConfigResponse{
|
||||
Diagnostics: tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("don't frobble")),
|
||||
}
|
||||
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Config: m,
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
diags := ctx.Validate()
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
}
|
||||
|
||||
for _, d := range diags {
|
||||
des := d.Description().Summary
|
||||
if !strings.Contains(des, "frobble") {
|
||||
t.Fatalf(`expected frobble, got %q`, des)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ type EvalApply struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalApply) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
change := *n.Change
|
||||
|
@ -54,7 +54,8 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
schema, _ := (*n.ProviderSchema).SchemaForResourceType(n.Addr.Resource.Mode, n.Addr.Resource.Type)
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
|
||||
diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type))
|
||||
return diags
|
||||
}
|
||||
|
||||
if n.CreateNew != nil {
|
||||
|
@ -69,15 +70,16 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
configVal, _, configDiags = ctx.EvaluateBlock(n.Config.Config, schema, nil, keyData)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
if !configVal.IsWhollyKnown() {
|
||||
return nil, fmt.Errorf(
|
||||
diags = diags.Append(fmt.Errorf(
|
||||
"configuration for %s still contains unknown values during apply (this is a bug in Terraform; please report it!)",
|
||||
absAddr,
|
||||
)
|
||||
))
|
||||
return diags
|
||||
}
|
||||
|
||||
metaConfigVal := cty.NullVal(cty.DynamicPseudoType)
|
||||
|
@ -99,7 +101,7 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +122,7 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
eqV := unmarkedBefore.Equals(unmarkedAfter)
|
||||
eq := eqV.IsKnown() && eqV.True()
|
||||
if change.Action == plans.Update && eq && !reflect.DeepEqual(beforePaths, afterPaths) {
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
resp := provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{
|
||||
|
@ -189,7 +191,7 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
// Bail early in this particular case, because an object that doesn't
|
||||
// conform to the schema can't be saved in the state anyway -- the
|
||||
// serializer will reject it.
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
// After this point we have a type-conforming result object and so we
|
||||
|
@ -350,21 +352,11 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
err := diags.Err()
|
||||
*n.Error = err
|
||||
log.Printf("[DEBUG] %s: apply errored, but we're indicating that via the Error pointer rather than returning it: %s", n.Addr.Absolute(ctx.Path()), err)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// we have to drop warning-only diagnostics for now
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.ErrWithWarnings()
|
||||
}
|
||||
|
||||
// log any warnings since we can't return them
|
||||
if e := diags.ErrWithWarnings(); e != nil {
|
||||
log.Printf("[WARN] EvalApply %s: %v", n.Addr, e)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalApplyPre is an EvalNode implementation that does the pre-Apply work
|
||||
|
@ -376,7 +368,8 @@ type EvalApplyPre struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalApplyPre) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalApplyPre) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
change := *n.Change
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
|
||||
|
@ -388,15 +381,15 @@ func (n *EvalApplyPre) Eval(ctx EvalContext) (interface{}, error) {
|
|||
priorState := change.Before
|
||||
plannedNewState := change.After
|
||||
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreApply(absAddr, n.Gen, change.Action, priorState, plannedNewState)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// EvalApplyPost is an EvalNode implementation that does the post-Apply work
|
||||
|
@ -408,7 +401,8 @@ type EvalApplyPost struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalApplyPost) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalApplyPost) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
state := *n.State
|
||||
|
||||
if resourceHasUserVisibleApply(n.Addr) {
|
||||
|
@ -419,20 +413,14 @@ func (n *EvalApplyPost) Eval(ctx EvalContext) (interface{}, error) {
|
|||
} else {
|
||||
newState = cty.NullVal(cty.DynamicPseudoType)
|
||||
}
|
||||
var err error
|
||||
if n.Error != nil {
|
||||
err = *n.Error
|
||||
}
|
||||
|
||||
hookErr := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostApply(absAddr, n.Gen, newState, err)
|
||||
})
|
||||
if hookErr != nil {
|
||||
return nil, hookErr
|
||||
}
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostApply(absAddr, n.Gen, newState, *n.Error)
|
||||
}))
|
||||
}
|
||||
|
||||
return nil, *n.Error
|
||||
diags = diags.Append(*n.Error)
|
||||
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalMaybeTainted is an EvalNode that takes the planned change, new value,
|
||||
|
@ -449,9 +437,9 @@ type EvalMaybeTainted struct {
|
|||
Error *error
|
||||
}
|
||||
|
||||
func (n *EvalMaybeTainted) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalMaybeTainted) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
if n.State == nil || n.Change == nil || n.Error == nil {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
state := *n.State
|
||||
|
@ -460,12 +448,12 @@ func (n *EvalMaybeTainted) Eval(ctx EvalContext) (interface{}, error) {
|
|||
|
||||
// nothing to do if everything went as planned
|
||||
if err == nil {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if state != nil && state.Status == states.ObjectTainted {
|
||||
log.Printf("[TRACE] EvalMaybeTainted: %s was already tainted, so nothing to do", n.Addr.Absolute(ctx.Path()))
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if change.Action == plans.Create {
|
||||
|
@ -482,7 +470,7 @@ func (n *EvalMaybeTainted) Eval(ctx EvalContext) (interface{}, error) {
|
|||
*n.State = state.AsTainted()
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceHasUserVisibleApply returns true if the given resource is one where
|
||||
|
@ -516,44 +504,44 @@ type EvalApplyProvisioners struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalApplyProvisioners) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalApplyProvisioners) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
state := *n.State
|
||||
if state == nil {
|
||||
log.Printf("[TRACE] EvalApplyProvisioners: %s has no state, so skipping provisioners", n.Addr)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
if n.When == configs.ProvisionerWhenCreate && n.CreateNew != nil && !*n.CreateNew {
|
||||
// If we're not creating a new resource, then don't run provisioners
|
||||
log.Printf("[TRACE] EvalApplyProvisioners: %s is not freshly-created, so no provisioning is required", n.Addr)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
if state.Status == states.ObjectTainted {
|
||||
// No point in provisioning an object that is already tainted, since
|
||||
// it's going to get recreated on the next apply anyway.
|
||||
log.Printf("[TRACE] EvalApplyProvisioners: %s is tainted, so skipping provisioning", n.Addr)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
provs := n.filterProvisioners()
|
||||
if len(provs) == 0 {
|
||||
// We have no provisioners, so don't do anything
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if n.Error != nil && *n.Error != nil {
|
||||
// We're already tainted, so just return out
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
{
|
||||
// Call pre hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreProvisionInstance(absAddr, state.Value)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Call pre hook
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreProvisionInstance(absAddr, state.Value)
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// If there are no errors, then we append it to our output error
|
||||
|
@ -561,25 +549,19 @@ func (n *EvalApplyProvisioners) Eval(ctx EvalContext) (interface{}, error) {
|
|||
err := n.apply(ctx, provs)
|
||||
if err != nil {
|
||||
*n.Error = multierror.Append(*n.Error, err)
|
||||
if n.Error == nil {
|
||||
return nil, err
|
||||
} else {
|
||||
log.Printf("[TRACE] EvalApplyProvisioners: %s provisioning failed, but we will continue anyway at the caller's request", absAddr)
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("[TRACE] EvalApplyProvisioners: %s provisioning failed, but we will continue anyway at the caller's request", absAddr)
|
||||
return nil
|
||||
}
|
||||
|
||||
{
|
||||
// Call post hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostProvisionInstance(absAddr, state.Value)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Call post hook
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostProvisionInstance(absAddr, state.Value)
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// filterProvisioners filters the provisioners on the resource to only
|
||||
|
|
|
@ -107,7 +107,7 @@ func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
|
|||
case HookActionHalt:
|
||||
// Return an early exit error to trigger an early exit
|
||||
log.Printf("[WARN] Early exit triggered by hook: %T", h)
|
||||
return EvalEarlyExitError{}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,9 @@ type EvalCheckPlannedChange struct {
|
|||
Planned, Actual **plans.ResourceInstanceChange
|
||||
}
|
||||
|
||||
func (n *EvalCheckPlannedChange) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalCheckPlannedChange) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
providerSchema := *n.ProviderSchema
|
||||
plannedChange := *n.Planned
|
||||
actualChange := *n.Actual
|
||||
|
@ -45,10 +47,10 @@ func (n *EvalCheckPlannedChange) Eval(ctx EvalContext) (interface{}, error) {
|
|||
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
return nil, fmt.Errorf("provider does not support %q", n.Addr.Resource.Type)
|
||||
diags = diags.Append(fmt.Errorf("provider does not support %q", n.Addr.Resource.Type))
|
||||
return diags
|
||||
}
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
|
||||
log.Printf("[TRACE] EvalCheckPlannedChange: Verifying that actual change (action %s) matches planned change (action %s)", actualChange.Action, plannedChange.Action)
|
||||
|
@ -96,7 +98,7 @@ func (n *EvalCheckPlannedChange) Eval(ctx EvalContext) (interface{}, error) {
|
|||
),
|
||||
))
|
||||
}
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalDiff is an EvalNode implementation that detects changes for a given
|
||||
|
@ -124,7 +126,9 @@ type EvalDiff struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalDiff) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
state := *n.State
|
||||
config := *n.Config
|
||||
provider := *n.Provider
|
||||
|
@ -137,26 +141,26 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
|
||||
if providerSchema == nil {
|
||||
return nil, fmt.Errorf("provider schema is unavailable for %s", n.Addr)
|
||||
diags = diags.Append(fmt.Errorf("provider schema is unavailable for %s", n.Addr))
|
||||
return diags
|
||||
}
|
||||
if n.ProviderAddr.Provider.Type == "" {
|
||||
panic(fmt.Sprintf("EvalDiff for %s does not have ProviderAddr set", n.Addr.Absolute(ctx.Path())))
|
||||
}
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Evaluate the configuration
|
||||
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
|
||||
diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type))
|
||||
return diags
|
||||
}
|
||||
forEach, _ := evaluateForEachExpression(n.Config.ForEach, ctx)
|
||||
keyData := EvalDataForInstanceKey(n.Addr.Key, forEach)
|
||||
origConfigVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
metaConfigVal := cty.NullVal(cty.DynamicPseudoType)
|
||||
|
@ -175,7 +179,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,18 +220,18 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
configValIgnored, ignoreChangeDiags := n.processIgnoreChanges(unmarkedPriorVal, unmarkedConfigVal)
|
||||
diags = diags.Append(ignoreChangeDiags)
|
||||
if ignoreChangeDiags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
proposedNewVal := objchange.ProposedNewObject(schema, unmarkedPriorVal, configValIgnored)
|
||||
|
||||
// Call pre-diff hook
|
||||
if !n.Stub {
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreDiff(absAddr, states.CurrentGen, priorVal, proposedNewVal)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,7 +246,8 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
},
|
||||
)
|
||||
if validateResp.Diagnostics.HasErrors() {
|
||||
return nil, validateResp.Diagnostics.InConfigBody(config.Config).Err()
|
||||
diags = diags.Append(validateResp.Diagnostics.InConfigBody(config.Config))
|
||||
return diags
|
||||
}
|
||||
|
||||
resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{
|
||||
|
@ -255,7 +260,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
})
|
||||
diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config))
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
plannedNewVal := resp.PlannedState
|
||||
|
@ -283,7 +288,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
))
|
||||
}
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
if errs := objchange.AssertPlanValid(schema, unmarkedPriorVal, configValIgnored, plannedNewVal); len(errs) > 0 {
|
||||
|
@ -313,7 +318,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
),
|
||||
))
|
||||
}
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,7 +385,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
}
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,7 +452,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
// append these new diagnostics if there's at least one error inside.
|
||||
if resp.Diagnostics.HasErrors() {
|
||||
diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config))
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
plannedNewVal = resp.PlannedState
|
||||
plannedPrivate = resp.PlannedPrivate
|
||||
|
@ -467,7 +472,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
))
|
||||
}
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,11 +511,11 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
|
||||
// Call post-refresh hook
|
||||
if !n.Stub {
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostDiff(absAddr, states.CurrentGen, action, priorVal, plannedNewVal)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -547,7 +552,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
func (n *EvalDiff) processIgnoreChanges(prior, config cty.Value) (cty.Value, tfdiags.Diagnostics) {
|
||||
|
@ -738,7 +743,9 @@ type EvalDiffDestroy struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalDiffDestroy) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
state := *n.State
|
||||
|
||||
|
@ -753,19 +760,19 @@ func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
|
|||
// If there is no state or our attributes object is null then we're already
|
||||
// destroyed.
|
||||
if state == nil || state.Value.IsNull() {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Call pre-diff hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreDiff(
|
||||
absAddr, n.DeposedKey.Generation(),
|
||||
state.Value,
|
||||
cty.NullVal(cty.DynamicPseudoType),
|
||||
)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Change is always the same for a destroy. We don't need the provider's
|
||||
|
@ -784,7 +791,7 @@ func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
|
||||
// Call post-diff hook
|
||||
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostDiff(
|
||||
absAddr,
|
||||
n.DeposedKey.Generation(),
|
||||
|
@ -792,9 +799,9 @@ func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
|
|||
change.Before,
|
||||
change.After,
|
||||
)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Update our output
|
||||
|
@ -805,7 +812,7 @@ func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
|
|||
*n.OutputState = nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalReduceDiff is an EvalNode implementation that takes a planned resource
|
||||
|
@ -829,7 +836,7 @@ type EvalReduceDiff struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalReduceDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalReduceDiff) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
in := *n.InChange
|
||||
out := in.Simplify(n.Destroy)
|
||||
if n.OutChange != nil {
|
||||
|
@ -842,7 +849,7 @@ func (n *EvalReduceDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
log.Printf("[TRACE] EvalReduceDiff: %s change simplified from %s to %s for apply node", n.Addr, in.Action, out.Action)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// EvalWriteDiff is an EvalNode implementation that saves a planned change
|
||||
|
@ -855,7 +862,9 @@ type EvalWriteDiff struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalWriteDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalWriteDiff) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
changes := ctx.Changes()
|
||||
addr := n.Addr.Absolute(ctx.Path())
|
||||
if n.Change == nil || *n.Change == nil {
|
||||
|
@ -866,7 +875,7 @@ func (n *EvalWriteDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
gen = n.DeposedKey
|
||||
}
|
||||
changes.RemoveResourceInstanceChange(addr, gen)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
providerSchema := *n.ProviderSchema
|
||||
|
@ -880,12 +889,14 @@ func (n *EvalWriteDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
|
||||
diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type))
|
||||
return diags
|
||||
}
|
||||
|
||||
csrc, err := change.Encode(schema.ImpliedType())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encode planned changes for %s: %s", addr, err)
|
||||
diags = diags.Append(fmt.Errorf("failed to encode planned changes for %s: %s", addr, err))
|
||||
return diags
|
||||
}
|
||||
|
||||
changes.AppendResourceInstanceChange(csrc)
|
||||
|
@ -895,5 +906,5 @@ func (n *EvalWriteDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
log.Printf("[TRACE] EvalWriteDiff: recorded %s change for %s deposed object %s", change.Action, addr, n.DeposedKey)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package terraform
|
||||
|
||||
// EvalEarlyExitError is a special error return value that can be returned
|
||||
// by eval nodes that does an early exit.
|
||||
type EvalEarlyExitError struct{}
|
||||
|
||||
func (EvalEarlyExitError) Error() string { return "early exit" }
|
|
@ -15,7 +15,7 @@ type evalReadDataApply struct {
|
|||
evalReadData
|
||||
}
|
||||
|
||||
func (n *evalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *evalReadDataApply) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
@ -26,22 +26,25 @@ func (n *evalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
|
||||
if n.ProviderSchema == nil || *n.ProviderSchema == nil {
|
||||
return nil, fmt.Errorf("provider schema not available for %s", n.Addr)
|
||||
diags = diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr))
|
||||
return diags
|
||||
}
|
||||
|
||||
if planned != nil && planned.Action != plans.Read {
|
||||
// If any other action gets in here then that's always a bug; this
|
||||
// EvalNode only deals with reading.
|
||||
return nil, fmt.Errorf(
|
||||
diags = diags.Append(fmt.Errorf(
|
||||
"invalid action %s for %s: only Read is supported (this is a bug in Terraform; please report it!)",
|
||||
planned.Action, absAddr,
|
||||
)
|
||||
))
|
||||
return diags
|
||||
}
|
||||
|
||||
if err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreApply(absAddr, states.CurrentGen, planned.Action, planned.Before, planned.After)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
config := *n.Config
|
||||
|
@ -49,7 +52,8 @@ func (n *evalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
return nil, fmt.Errorf("provider %q does not support data source %q", n.ProviderAddr.Provider.String(), n.Addr.Resource.Type)
|
||||
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ProviderAddr.Provider.String(), n.Addr.Resource.Type))
|
||||
return diags
|
||||
}
|
||||
|
||||
forEach, _ := evaluateForEachExpression(config.ForEach, ctx)
|
||||
|
@ -58,13 +62,13 @@ func (n *evalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
newVal, readDiags := n.readDataSource(ctx, configVal)
|
||||
diags = diags.Append(readDiags)
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
*n.State = &states.ResourceInstanceObject{
|
||||
|
@ -72,11 +76,9 @@ func (n *evalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
|
|||
Status: states.ObjectReady,
|
||||
}
|
||||
|
||||
if err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostApply(absAddr, states.CurrentGen, newVal, diags.Err())
|
||||
}); err != nil {
|
||||
diags = diags.Append(err)
|
||||
}
|
||||
}))
|
||||
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -21,14 +21,15 @@ type evalReadDataPlan struct {
|
|||
evalReadData
|
||||
}
|
||||
|
||||
func (n *evalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *evalReadDataPlan) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
var configVal cty.Value
|
||||
|
||||
if n.ProviderSchema == nil || *n.ProviderSchema == nil {
|
||||
return nil, fmt.Errorf("provider schema not available for %s", n.Addr)
|
||||
diags = diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr))
|
||||
return diags
|
||||
}
|
||||
|
||||
config := *n.Config
|
||||
|
@ -36,7 +37,8 @@ func (n *evalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
|
|||
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
return nil, fmt.Errorf("provider %q does not support data source %q", n.ProviderAddr.Provider.String(), n.Addr.Resource.Type)
|
||||
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ProviderAddr.Provider.String(), n.Addr.Resource.Type))
|
||||
return diags
|
||||
}
|
||||
|
||||
objTy := schema.ImpliedType()
|
||||
|
@ -52,7 +54,7 @@ func (n *evalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
|
|||
configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
configKnown := configVal.IsWhollyKnown()
|
||||
|
@ -69,11 +71,11 @@ func (n *evalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
|
|||
|
||||
proposedNewVal := objchange.PlannedDataResourceObject(schema, configVal)
|
||||
|
||||
if err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreDiff(absAddr, states.CurrentGen, priorVal, proposedNewVal)
|
||||
}); err != nil {
|
||||
diags = diags.Append(err)
|
||||
return nil, diags.ErrWithWarnings()
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Apply detects that the data source will need to be read by the After
|
||||
|
@ -93,13 +95,11 @@ func (n *evalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
|
|||
Status: states.ObjectPlanned,
|
||||
}
|
||||
|
||||
if err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostDiff(absAddr, states.CurrentGen, plans.Read, priorVal, proposedNewVal)
|
||||
}); err != nil {
|
||||
diags = diags.Append(err)
|
||||
}
|
||||
}))
|
||||
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
// We have a complete configuration with no dependencies to wait on, so we
|
||||
|
@ -107,7 +107,7 @@ func (n *evalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
|
|||
newVal, readDiags := n.readDataSource(ctx, configVal)
|
||||
diags = diags.Append(readDiags)
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
// if we have a prior value, we can check for any irregularities in the response
|
||||
|
@ -137,13 +137,10 @@ func (n *evalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
|
|||
Status: states.ObjectReady,
|
||||
}
|
||||
|
||||
if err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostDiff(absAddr, states.CurrentGen, plans.Update, priorVal, newVal)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, diags.ErrWithWarnings()
|
||||
}))
|
||||
return diags
|
||||
}
|
||||
|
||||
// forcePlanRead determines if we need to override the usual behavior of
|
||||
|
|
|
@ -29,7 +29,7 @@ type EvalRefresh struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalRefresh) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
state := *n.State
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
|
||||
|
@ -38,13 +38,14 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
|
|||
// If we have no state, we don't do any refreshing
|
||||
if state == nil {
|
||||
log.Printf("[DEBUG] refresh: %s: no state, so not refreshing", n.Addr.Absolute(ctx.Path()))
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
schema, _ := (*n.ProviderSchema).SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
|
||||
diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type))
|
||||
return diags
|
||||
}
|
||||
|
||||
metaConfigVal := cty.NullVal(cty.DynamicPseudoType)
|
||||
|
@ -66,18 +67,18 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
|
|||
metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call pre-refresh hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreRefresh(absAddr, states.CurrentGen, state.Value)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, diags.ErrWithWarnings()
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Refresh!
|
||||
|
@ -100,7 +101,7 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
|
|||
resp := provider.ReadResource(req)
|
||||
diags = diags.Append(resp.Diagnostics)
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
if resp.NewState == cty.NilVal {
|
||||
|
@ -121,7 +122,7 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
|
|||
))
|
||||
}
|
||||
if diags.HasErrors() {
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
// We have no way to exempt provider using the legacy SDK from this check,
|
||||
|
@ -142,11 +143,11 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
|
|||
newState.CreateBeforeDestroy = state.CreateBeforeDestroy
|
||||
|
||||
// Call post-refresh hook
|
||||
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostRefresh(absAddr, states.CurrentGen, priorVal, newState.Value)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Mark the value if necessary
|
||||
|
@ -158,5 +159,5 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
|
|||
*n.Output = newState
|
||||
}
|
||||
|
||||
return nil, diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -37,7 +37,9 @@ type EvalReadState struct {
|
|||
Output **states.ResourceInstanceObject
|
||||
}
|
||||
|
||||
func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalReadState) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if n.Provider == nil || *n.Provider == nil {
|
||||
panic("EvalReadState used with no Provider object")
|
||||
}
|
||||
|
@ -52,33 +54,35 @@ func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
|
|||
if src == nil {
|
||||
// Presumably we only have deposed objects, then.
|
||||
log.Printf("[TRACE] EvalReadState: no state present for %s", absAddr)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
schema, currentVersion := (*n.ProviderSchema).SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Shouldn't happen since we should've failed long ago if no schema is present
|
||||
return nil, fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", absAddr)
|
||||
diags = diags.Append(fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", absAddr))
|
||||
return diags
|
||||
}
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
src, diags = UpgradeResourceState(absAddr, *n.Provider, src, schema, currentVersion)
|
||||
if diags.HasErrors() {
|
||||
// Note that we don't have any channel to return warnings here. We'll
|
||||
// accept that for now since warnings during a schema upgrade would
|
||||
// be pretty weird anyway, since this operation is supposed to seem
|
||||
// invisible to the user.
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
obj, err := src.Decode(schema.ImpliedType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
diags = diags.Append(err)
|
||||
return diags
|
||||
}
|
||||
|
||||
if n.Output != nil {
|
||||
*n.Output = obj
|
||||
}
|
||||
return obj, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalReadStateDeposed is an EvalNode implementation that reads the
|
||||
|
@ -102,7 +106,9 @@ type EvalReadStateDeposed struct {
|
|||
Output **states.ResourceInstanceObject
|
||||
}
|
||||
|
||||
func (n *EvalReadStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalReadStateDeposed) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if n.Provider == nil || *n.Provider == nil {
|
||||
panic("EvalReadStateDeposed used with no Provider object")
|
||||
}
|
||||
|
@ -112,7 +118,8 @@ func (n *EvalReadStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
|||
|
||||
key := n.Key
|
||||
if key == states.NotDeposed {
|
||||
return nil, fmt.Errorf("EvalReadStateDeposed used with no instance key; this is a bug in Terraform and should be reported")
|
||||
diags = diags.Append(fmt.Errorf("EvalReadStateDeposed used with no instance key; this is a bug in Terraform and should be reported"))
|
||||
return diags
|
||||
}
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
log.Printf("[TRACE] EvalReadStateDeposed: reading state for %s deposed object %s", absAddr, n.Key)
|
||||
|
@ -121,32 +128,34 @@ func (n *EvalReadStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
|||
if src == nil {
|
||||
// Presumably we only have deposed objects, then.
|
||||
log.Printf("[TRACE] EvalReadStateDeposed: no state present for %s deposed object %s", absAddr, n.Key)
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
schema, currentVersion := (*n.ProviderSchema).SchemaForResourceAddr(n.Addr.ContainingResource())
|
||||
if schema == nil {
|
||||
// Shouldn't happen since we should've failed long ago if no schema is present
|
||||
return nil, fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", absAddr)
|
||||
diags = diags.Append(fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", absAddr))
|
||||
return diags
|
||||
}
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
src, diags = UpgradeResourceState(absAddr, *n.Provider, src, schema, currentVersion)
|
||||
if diags.HasErrors() {
|
||||
// Note that we don't have any channel to return warnings here. We'll
|
||||
// accept that for now since warnings during a schema upgrade would
|
||||
// be pretty weird anyway, since this operation is supposed to seem
|
||||
// invisible to the user.
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
obj, err := src.Decode(schema.ImpliedType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
diags = diags.Append(err)
|
||||
return diags
|
||||
}
|
||||
if n.Output != nil {
|
||||
*n.Output = obj
|
||||
}
|
||||
return obj, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// UpdateStateHook calls the PostStateUpdate hook with the current state.
|
||||
|
@ -173,7 +182,7 @@ type evalWriteEmptyState struct {
|
|||
EvalWriteState
|
||||
}
|
||||
|
||||
func (n *evalWriteEmptyState) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *evalWriteEmptyState) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var state *states.ResourceInstanceObject
|
||||
n.State = &state
|
||||
return n.EvalWriteState.Eval(ctx)
|
||||
|
@ -204,7 +213,9 @@ type EvalWriteState struct {
|
|||
targetState phaseState
|
||||
}
|
||||
|
||||
func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalWriteState) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if n.State == nil {
|
||||
// Note that a pointer _to_ nil is valid here, indicating the total
|
||||
// absense of an object as we'd see during destroy.
|
||||
|
@ -223,14 +234,15 @@ func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
|
||||
if n.ProviderAddr.Provider.Type == "" {
|
||||
return nil, fmt.Errorf("failed to write state for %s: missing provider type", absAddr)
|
||||
diags = diags.Append(fmt.Errorf("failed to write state for %s: missing provider type", absAddr))
|
||||
return diags
|
||||
}
|
||||
obj := *n.State
|
||||
if obj == nil || obj.Value.IsNull() {
|
||||
// No need to encode anything: we'll just write it directly.
|
||||
state.SetResourceInstanceCurrent(absAddr, nil, n.ProviderAddr)
|
||||
log.Printf("[TRACE] EvalWriteState: removing state object for %s", absAddr)
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// store the new deps in the state
|
||||
|
@ -255,15 +267,17 @@ func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
|
|||
// It shouldn't be possible to get this far in any real scenario
|
||||
// without a schema, but we might end up here in contrived tests that
|
||||
// fail to set up their world properly.
|
||||
return nil, fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr)
|
||||
diags = diags.Append(fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr))
|
||||
return diags
|
||||
}
|
||||
src, err := obj.Encode(schema.ImpliedType(), currentVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encode %s in state: %s", absAddr, err)
|
||||
diags = diags.Append(fmt.Errorf("failed to encode %s in state: %s", absAddr, err))
|
||||
return diags
|
||||
}
|
||||
|
||||
state.SetResourceInstanceCurrent(absAddr, src, n.ProviderAddr)
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalWriteStateDeposed is an EvalNode implementation that writes
|
||||
|
@ -286,7 +300,9 @@ type EvalWriteStateDeposed struct {
|
|||
ProviderAddr addrs.AbsProviderConfig
|
||||
}
|
||||
|
||||
func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if n.State == nil {
|
||||
// Note that a pointer _to_ nil is valid here, indicating the total
|
||||
// absense of an object as we'd see during destroy.
|
||||
|
@ -299,7 +315,8 @@ func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
|||
|
||||
if key == states.NotDeposed {
|
||||
// should never happen
|
||||
return nil, fmt.Errorf("can't save deposed object for %s without a deposed key; this is a bug in Terraform that should be reported", absAddr)
|
||||
diags = diags.Append(fmt.Errorf("can't save deposed object for %s without a deposed key; this is a bug in Terraform that should be reported", absAddr))
|
||||
return diags
|
||||
}
|
||||
|
||||
obj := *n.State
|
||||
|
@ -307,7 +324,7 @@ func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
|||
// No need to encode anything: we'll just write it directly.
|
||||
state.SetResourceInstanceDeposed(absAddr, key, nil, n.ProviderAddr)
|
||||
log.Printf("[TRACE] EvalWriteStateDeposed: removing state object for %s deposed %s", absAddr, key)
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
if n.ProviderSchema == nil || *n.ProviderSchema == nil {
|
||||
// Should never happen, unless our state object is nil
|
||||
|
@ -319,16 +336,18 @@ func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
|||
// It shouldn't be possible to get this far in any real scenario
|
||||
// without a schema, but we might end up here in contrived tests that
|
||||
// fail to set up their world properly.
|
||||
return nil, fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr)
|
||||
diags = diags.Append(fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr))
|
||||
return diags
|
||||
}
|
||||
src, err := obj.Encode(schema.ImpliedType(), currentVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encode %s in state: %s", absAddr, err)
|
||||
diags = diags.Append(fmt.Errorf("failed to encode %s in state: %s", absAddr, err))
|
||||
return diags
|
||||
}
|
||||
|
||||
log.Printf("[TRACE] EvalWriteStateDeposed: writing state object for %s deposed %s", absAddr, key)
|
||||
state.SetResourceInstanceDeposed(absAddr, key, src, n.ProviderAddr)
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalDeposeState is an EvalNode implementation that moves the current object
|
||||
|
@ -353,7 +372,7 @@ type EvalDeposeState struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalDeposeState) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalDeposeState) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
state := ctx.State()
|
||||
|
||||
|
@ -370,7 +389,7 @@ func (n *EvalDeposeState) Eval(ctx EvalContext) (interface{}, error) {
|
|||
*n.OutputKey = key
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// EvalMaybeRestoreDeposedObject is an EvalNode implementation that will
|
||||
|
@ -405,7 +424,9 @@ type EvalMaybeRestoreDeposedObject struct {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalMaybeRestoreDeposedObject) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalMaybeRestoreDeposedObject) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
absAddr := n.Addr.Absolute(ctx.Path())
|
||||
dk := *n.Key
|
||||
state := ctx.State()
|
||||
|
@ -414,7 +435,6 @@ func (n *EvalMaybeRestoreDeposedObject) Eval(ctx EvalContext) (interface{}, erro
|
|||
// This should never happen, and so it always indicates a bug.
|
||||
// We should evaluate this node only if we've previously deposed
|
||||
// an object as part of the same operation.
|
||||
var diags tfdiags.Diagnostics
|
||||
if n.PlannedChange != nil && *n.PlannedChange != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
|
@ -434,7 +454,7 @@ func (n *EvalMaybeRestoreDeposedObject) Eval(ctx EvalContext) (interface{}, erro
|
|||
),
|
||||
))
|
||||
}
|
||||
return nil, diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
restored := state.MaybeRestoreResourceInstanceDeposed(absAddr, dk)
|
||||
|
@ -444,7 +464,7 @@ func (n *EvalMaybeRestoreDeposedObject) Eval(ctx EvalContext) (interface{}, erro
|
|||
log.Printf("[TRACE] EvalMaybeRestoreDeposedObject: %s deposed object %s remains deposed", absAddr, dk)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalRefreshLifecycle is an EvalNode implementation that updates
|
||||
|
@ -461,21 +481,21 @@ type EvalRefreshLifecycle struct {
|
|||
ForceCreateBeforeDestroy bool
|
||||
}
|
||||
|
||||
func (n *EvalRefreshLifecycle) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalRefreshLifecycle) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
state := *n.State
|
||||
if state == nil {
|
||||
// no existing state
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// In 0.13 we could be refreshing a resource with no config.
|
||||
// We should be operating on managed resource, but check here to be certain
|
||||
if n.Config == nil || n.Config.Managed == nil {
|
||||
log.Printf("[WARN] EvalRefreshLifecycle: no Managed config value found in instance state for %q", n.Addr)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
state.CreateBeforeDestroy = n.Config.Managed.CreateBeforeDestroy || n.ForceCreateBeforeDestroy
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -67,15 +67,12 @@ func TestEvalReadState(t *testing.T) {
|
|||
ctx.StateState = state.SyncWrapper()
|
||||
ctx.PathPath = addrs.RootModuleInstance
|
||||
|
||||
result, err := c.Node.Eval(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("[%s] Got err: %#v", k, err)
|
||||
diags := c.Node.Eval(ctx)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("[%s] Got err: %#v", k, diags.ErrWithWarnings())
|
||||
}
|
||||
|
||||
expected := c.ExpectedInstanceId
|
||||
if !(result != nil && instanceObjectIdForTests(result.(*states.ResourceInstanceObject)) == expected) {
|
||||
t.Fatalf("[%s] Expected return with ID %#v, got: %#v", k, expected, result)
|
||||
}
|
||||
|
||||
if !(output != nil && output.Value.GetAttr("id") == cty.StringVal(expected)) {
|
||||
t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, output)
|
||||
|
@ -141,15 +138,12 @@ func TestEvalReadStateDeposed(t *testing.T) {
|
|||
ctx.StateState = state.SyncWrapper()
|
||||
ctx.PathPath = addrs.RootModuleInstance
|
||||
|
||||
result, err := c.Node.Eval(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("[%s] Got err: %#v", k, err)
|
||||
diags := c.Node.Eval(ctx)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("[%s] Got err: %#v", k, diags.ErrWithWarnings())
|
||||
}
|
||||
|
||||
expected := c.ExpectedInstanceId
|
||||
if !(result != nil && instanceObjectIdForTests(result.(*states.ResourceInstanceObject)) == expected) {
|
||||
t.Fatalf("[%s] Expected return with ID %#v, got: %#v", k, expected, result)
|
||||
}
|
||||
|
||||
if !(output != nil && output.Value.GetAttr("id") == cty.StringVal(expected)) {
|
||||
t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, output)
|
||||
|
@ -194,9 +188,9 @@ func TestEvalWriteState(t *testing.T) {
|
|||
ProviderSchema: &providerSchema,
|
||||
ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("aws")),
|
||||
}
|
||||
_, err := node.Eval(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Got err: %#v", err)
|
||||
diags := node.Eval(ctx)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("Got err: %#v", diags.ErrWithWarnings())
|
||||
}
|
||||
|
||||
checkStateString(t, state, `
|
||||
|
@ -241,9 +235,9 @@ func TestEvalWriteStateDeposed(t *testing.T) {
|
|||
ProviderSchema: &providerSchema,
|
||||
ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("aws")),
|
||||
}
|
||||
_, err := node.Eval(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Got err: %#v", err)
|
||||
diags := node.Eval(ctx)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("Got err: %#v", diags.ErrWithWarnings())
|
||||
}
|
||||
|
||||
checkStateString(t, state, `
|
||||
|
|
|
@ -15,54 +15,6 @@ import (
|
|||
"github.com/zclconf/go-cty/cty/gocty"
|
||||
)
|
||||
|
||||
// EvalValidateCount is an EvalNode implementation that validates
|
||||
// the count of a resource.
|
||||
type EvalValidateCount struct {
|
||||
Resource *configs.Resource
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalValidateCount) Eval(ctx EvalContext) (interface{}, error) {
|
||||
var diags tfdiags.Diagnostics
|
||||
var count int
|
||||
var err error
|
||||
|
||||
val, valDiags := ctx.EvaluateExpr(n.Resource.Count, cty.Number, nil)
|
||||
diags = diags.Append(valDiags)
|
||||
if valDiags.HasErrors() {
|
||||
goto RETURN
|
||||
}
|
||||
if val.IsNull() || !val.IsKnown() {
|
||||
goto RETURN
|
||||
}
|
||||
|
||||
err = gocty.FromCtyValue(val, &count)
|
||||
if err != nil {
|
||||
// The EvaluateExpr call above already guaranteed us a number value,
|
||||
// so if we end up here then we have something that is out of range
|
||||
// for an int, and the error message will include a description of
|
||||
// the valid range.
|
||||
rawVal := val.AsBigFloat()
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid count value",
|
||||
Detail: fmt.Sprintf("The number %s is not a valid count value: %s.", rawVal, err),
|
||||
Subject: n.Resource.Count.Range().Ptr(),
|
||||
})
|
||||
} else if count < 0 {
|
||||
rawVal := val.AsBigFloat()
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid count value",
|
||||
Detail: fmt.Sprintf("The number %s is not a valid count value: count must not be negative.", rawVal),
|
||||
Subject: n.Resource.Count.Range().Ptr(),
|
||||
})
|
||||
}
|
||||
|
||||
RETURN:
|
||||
return nil, diags.NonFatalErr()
|
||||
}
|
||||
|
||||
// EvalValidateProvisioner validates the configuration of a provisioner
|
||||
// belonging to a resource. The provisioner config is expected to contain the
|
||||
// merged connection configurations.
|
||||
|
|
|
@ -20,7 +20,7 @@ type EvalValidateSelfRef struct {
|
|||
ProviderSchema **ProviderSchema
|
||||
}
|
||||
|
||||
func (n *EvalValidateSelfRef) Eval(ctx EvalContext) (interface{}, error) {
|
||||
func (n *EvalValidateSelfRef) Eval(ctx EvalContext) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
addr := n.Addr
|
||||
|
||||
|
@ -33,7 +33,8 @@ func (n *EvalValidateSelfRef) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
|
||||
if n.ProviderSchema == nil || *n.ProviderSchema == nil {
|
||||
return nil, fmt.Errorf("provider schema unavailable while validating %s for self-references; this is a bug in Terraform and should be reported", addr)
|
||||
diags = diags.Append(fmt.Errorf("provider schema unavailable while validating %s for self-references; this is a bug in Terraform and should be reported", addr))
|
||||
return diags
|
||||
}
|
||||
|
||||
providerSchema := *n.ProviderSchema
|
||||
|
@ -46,7 +47,8 @@ func (n *EvalValidateSelfRef) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
|
||||
if schema == nil {
|
||||
return nil, fmt.Errorf("no schema available for %s to validate for self-references; this is a bug in Terraform and should be reported", addr)
|
||||
diags = diags.Append(fmt.Errorf("no schema available for %s to validate for self-references; this is a bug in Terraform and should be reported", addr))
|
||||
return diags
|
||||
}
|
||||
|
||||
refs, _ := lang.ReferencesInBlock(n.Config, schema)
|
||||
|
@ -63,5 +65,5 @@ func (n *EvalValidateSelfRef) Eval(ctx EvalContext) (interface{}, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return nil, diags.NonFatalErr()
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hcltest"
|
||||
|
@ -98,11 +97,7 @@ func TestEvalValidateSelfRef(t *testing.T) {
|
|||
Config: body,
|
||||
ProviderSchema: &ps,
|
||||
}
|
||||
result, err := n.Eval(nil)
|
||||
if result != nil {
|
||||
t.Fatal("result should always be nil")
|
||||
}
|
||||
diags := tfdiags.Diagnostics(nil).Append(err)
|
||||
diags := n.Eval(nil)
|
||||
if diags.HasErrors() != test.Err {
|
||||
if test.Err {
|
||||
t.Errorf("unexpected success; want error")
|
||||
|
|
|
@ -18,14 +18,12 @@ import (
|
|||
// This must be used only after any side-effects that make the value of the
|
||||
// variable available for use in expression evaluation, such as
|
||||
// EvalModuleCallArgument for variables in descendent modules.
|
||||
func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *configs.Variable, expr hcl.Expression, ctx EvalContext) error {
|
||||
func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *configs.Variable, expr hcl.Expression, ctx EvalContext) (diags tfdiags.Diagnostics) {
|
||||
if config == nil || len(config.Validations) == 0 {
|
||||
log.Printf("[TRACE] evalVariableValidations: not active for %s, so skipping", addr)
|
||||
return nil
|
||||
}
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Variable nodes evaluate in the parent module to where they were declared
|
||||
// because the value expression (n.Expr, if set) comes from the calling
|
||||
// "module" block in the parent module.
|
||||
|
@ -105,5 +103,5 @@ func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *config
|
|||
}
|
||||
}
|
||||
|
||||
return diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package terraform
|
||||
|
||||
import "github.com/hashicorp/terraform/tfdiags"
|
||||
|
||||
// GraphNodeExecutable is the interface that graph nodes must implement to
|
||||
// enable execution. This is an alternative to GraphNodeEvalable, which is in
|
||||
// the process of being removed. A given graph node should _not_ implement both
|
||||
// GraphNodeExecutable and GraphNodeEvalable.
|
||||
type GraphNodeExecutable interface {
|
||||
Execute(EvalContext, walkOperation) error
|
||||
Execute(EvalContext, walkOperation) tfdiags.Diagnostics
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ type ContextGraphWalker struct {
|
|||
// is in progress.
|
||||
NonFatalDiagnostics tfdiags.Diagnostics
|
||||
|
||||
errorLock sync.Mutex
|
||||
once sync.Once
|
||||
contexts map[string]*BuiltinEvalContext
|
||||
contextLock sync.Mutex
|
||||
|
@ -123,39 +122,7 @@ func (w *ContextGraphWalker) init() {
|
|||
func (w *ContextGraphWalker) Execute(ctx EvalContext, n GraphNodeExecutable) tfdiags.Diagnostics {
|
||||
// Acquire a lock on the semaphore
|
||||
w.Context.parallelSem.Acquire()
|
||||
defer w.Context.parallelSem.Release()
|
||||
|
||||
err := n.Execute(ctx, w.Operation)
|
||||
|
||||
// Release the semaphore
|
||||
w.Context.parallelSem.Release()
|
||||
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Acquire the lock because anything is going to require a lock.
|
||||
w.errorLock.Lock()
|
||||
defer w.errorLock.Unlock()
|
||||
|
||||
// If the error is non-fatal then we'll accumulate its diagnostics in our
|
||||
// non-fatal list, rather than returning it directly, so that the graph
|
||||
// walk can continue.
|
||||
if nferr, ok := err.(tfdiags.NonFatalError); ok {
|
||||
w.NonFatalDiagnostics = w.NonFatalDiagnostics.Append(nferr.Diagnostics)
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we early exit, it isn't an error.
|
||||
if _, isEarlyExit := err.(EvalEarlyExitError); isEarlyExit {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise, we'll let our usual diagnostics machinery figure out how to
|
||||
// unpack this as one or more diagnostic messages and return that. If we
|
||||
// get down here then the returned diagnostics will contain at least one
|
||||
// error, causing the graph walk to halt.
|
||||
var diags tfdiags.Diagnostics
|
||||
diags = diags.Append(err)
|
||||
return diags
|
||||
|
||||
return n.Execute(ctx, w.Operation)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
@ -76,11 +77,7 @@ func (h *stopHook) PostStateUpdate(new *states.State) (HookAction, error) {
|
|||
|
||||
func (h *stopHook) hook() (HookAction, error) {
|
||||
if h.Stopped() {
|
||||
// FIXME: This should really return an error since stopping partway
|
||||
// through is not a successful run-to-completion, but we'll need to
|
||||
// introduce that cautiously since existing automation solutions may
|
||||
// be depending on this behavior.
|
||||
return HookActionHalt, nil
|
||||
return HookActionHalt, errors.New("execution halted")
|
||||
}
|
||||
|
||||
return HookActionContinue, nil
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// NodeCountBoundary fixes up any transitions between "each modes" in objects
|
||||
|
@ -14,12 +15,14 @@ type NodeCountBoundary struct {
|
|||
Config *configs.Config
|
||||
}
|
||||
|
||||
var _ GraphNodeExecutable = (*NodeCountBoundary)(nil)
|
||||
|
||||
func (n *NodeCountBoundary) Name() string {
|
||||
return "meta.count-boundary (EachMode fixup)"
|
||||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeCountBoundary) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeCountBoundary) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
// We'll temporarily lock the state to grab the modules, then work on each
|
||||
// one separately while taking a lock again for each separate resource.
|
||||
// This means that if another caller concurrently adds a module here while
|
||||
|
@ -42,10 +45,11 @@ func (n *NodeCountBoundary) Execute(ctx EvalContext, op walkOperation) error {
|
|||
continue
|
||||
}
|
||||
if err := n.fixModule(ctx, addr); err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
return diags
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
||||
func (n *NodeCountBoundary) fixModule(ctx EvalContext, moduleAddr addrs.ModuleInstance) error {
|
||||
|
|
|
@ -53,9 +53,9 @@ func TestNodeCountBoundaryExecute(t *testing.T) {
|
|||
}
|
||||
node := NodeCountBoundary{Config: config}
|
||||
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
if !state.HasResources() {
|
||||
t.Fatal("resources missing from state")
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package terraform
|
||||
|
||||
import "log"
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// NodeDestroyableDataResourceInstance represents a resource that is "destroyable":
|
||||
// it is ready to be destroyed.
|
||||
|
@ -13,7 +17,7 @@ var (
|
|||
)
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeDestroyableDataResourceInstance) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeDestroyableDataResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
||||
log.Printf("[TRACE] NodeDestroyableDataResourceInstance: removing state object for %s", n.Addr)
|
||||
ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
|
||||
return nil
|
||||
|
|
|
@ -36,9 +36,9 @@ func TestNodeDataDestroyExecute(t *testing.T) {
|
|||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
}}
|
||||
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %v", diags.Err())
|
||||
}
|
||||
|
||||
// verify resource removed from state
|
||||
|
|
|
@ -128,10 +128,7 @@ func (n *NodeLocal) References() []*addrs.Reference {
|
|||
// NodeLocal.Execute is an Execute implementation that evaluates the
|
||||
// expression for a local value and writes it into a transient part of
|
||||
// the state.
|
||||
func (n *NodeLocal) Execute(ctx EvalContext, op walkOperation) error {
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
func (n *NodeLocal) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
expr := n.Config.Expr
|
||||
addr := n.Addr.LocalValue
|
||||
|
||||
|
@ -150,23 +147,24 @@ func (n *NodeLocal) Execute(ctx EvalContext, op walkOperation) error {
|
|||
}
|
||||
}
|
||||
if diags.HasErrors() {
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
val, moreDiags := ctx.EvaluateExpr(expr, cty.DynamicPseudoType, nil)
|
||||
diags = diags.Append(moreDiags)
|
||||
if moreDiags.HasErrors() {
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
state := ctx.State()
|
||||
if state == nil {
|
||||
return fmt.Errorf("cannot write local value to nil state")
|
||||
diags = diags.Append(fmt.Errorf("cannot write local value to nil state"))
|
||||
return diags
|
||||
}
|
||||
|
||||
state.SetLocalValue(addr.Absolute(ctx.Path()), val)
|
||||
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// dag.GraphNodeDotter impl.
|
||||
|
|
|
@ -99,7 +99,7 @@ func (n *nodeExpandModule) ReferenceOutside() (selfPath, referencePath addrs.Mod
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
expander := ctx.InstanceExpander()
|
||||
_, call := n.Addr.Call()
|
||||
|
||||
|
@ -110,16 +110,18 @@ func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) error {
|
|||
ctx = ctx.WithPath(module)
|
||||
switch {
|
||||
case n.ModuleCall.Count != nil:
|
||||
count, diags := evaluateCountExpression(n.ModuleCall.Count, ctx)
|
||||
count, ctDiags := evaluateCountExpression(n.ModuleCall.Count, ctx)
|
||||
diags = diags.Append(ctDiags)
|
||||
if diags.HasErrors() {
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
expander.SetModuleCount(module, call, count)
|
||||
|
||||
case n.ModuleCall.ForEach != nil:
|
||||
forEach, diags := evaluateForEachExpression(n.ModuleCall.ForEach, ctx)
|
||||
forEach, feDiags := evaluateForEachExpression(n.ModuleCall.ForEach, ctx)
|
||||
diags = diags.Append(feDiags)
|
||||
if diags.HasErrors() {
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
expander.SetModuleForEach(module, call, forEach)
|
||||
|
||||
|
@ -128,7 +130,7 @@ func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) error {
|
|||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return diags
|
||||
|
||||
}
|
||||
|
||||
|
@ -146,6 +148,7 @@ type nodeCloseModule struct {
|
|||
var (
|
||||
_ GraphNodeReferenceable = (*nodeCloseModule)(nil)
|
||||
_ GraphNodeReferenceOutside = (*nodeCloseModule)(nil)
|
||||
_ GraphNodeExecutable = (*nodeCloseModule)(nil)
|
||||
)
|
||||
|
||||
func (n *nodeCloseModule) ModulePath() addrs.Module {
|
||||
|
@ -170,7 +173,7 @@ func (n *nodeCloseModule) Name() string {
|
|||
return n.Addr.String() + " (close)"
|
||||
}
|
||||
|
||||
func (n *nodeCloseModule) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *nodeCloseModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
switch op {
|
||||
case walkApply, walkDestroy:
|
||||
state := ctx.State().Lock()
|
||||
|
@ -206,10 +209,11 @@ type nodeValidateModule struct {
|
|||
nodeExpandModule
|
||||
}
|
||||
|
||||
var _ GraphNodeExecutable = (*nodeValidateModule)(nil)
|
||||
|
||||
// GraphNodeEvalable
|
||||
func (n *nodeValidateModule) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *nodeValidateModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
_, call := n.Addr.Call()
|
||||
var diags tfdiags.Diagnostics
|
||||
expander := ctx.InstanceExpander()
|
||||
|
||||
// Modules all evaluate to single instances during validation, only to
|
||||
|
@ -238,9 +242,5 @@ func (n *nodeValidateModule) Execute(ctx EvalContext, op walkOperation) error {
|
|||
expander.SetModuleSingle(module, call)
|
||||
}
|
||||
|
||||
if diags.HasErrors() {
|
||||
return diags.ErrWithWarnings()
|
||||
}
|
||||
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@ func TestNodeCloseModuleExecute(t *testing.T) {
|
|||
StateState: state.SyncWrapper(),
|
||||
}
|
||||
node := nodeCloseModule{addrs.Module{"child"}}
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
|
||||
// Since module.child has no resources, it should be removed
|
||||
|
@ -62,9 +62,9 @@ func TestNodeCloseModuleExecute(t *testing.T) {
|
|||
}
|
||||
node := nodeCloseModule{addrs.Module{"child"}}
|
||||
|
||||
err := node.Execute(ctx, walkImport)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkImport)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
if _, ok := state.Modules["module.child"]; !ok {
|
||||
t.Fatal("module.child was removed from state, expected no-op")
|
||||
|
@ -87,9 +87,9 @@ func TestNodeValidateModuleExecute(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %v", diags.Err())
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/hashicorp/terraform/dag"
|
||||
"github.com/hashicorp/terraform/instances"
|
||||
"github.com/hashicorp/terraform/lang"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
)
|
||||
|
@ -141,7 +142,7 @@ func (n *nodeModuleVariable) ModulePath() addrs.Module {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
// If we have no value, do nothing
|
||||
if n.Expr == nil {
|
||||
return nil
|
||||
|
@ -155,13 +156,15 @@ func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) error {
|
|||
switch op {
|
||||
case walkValidate:
|
||||
vals, err = n.EvalModuleCallArgument(ctx, true)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
default:
|
||||
vals, err = n.EvalModuleCallArgument(ctx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -246,11 +246,10 @@ func (n *NodeApplyableOutput) References() []*addrs.Reference {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) error {
|
||||
var diags tfdiags.Diagnostics
|
||||
func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
state := ctx.State()
|
||||
if state == nil {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
changes := ctx.Changes() // may be nil, if we're not working on a changeset
|
||||
|
@ -297,9 +296,24 @@ func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) error {
|
|||
// marked as unknown. If the evaluator was able to find a type
|
||||
// for the value in spite of the error then we'll use it.
|
||||
n.setValue(state, changes, cty.UnknownVal(val.Type()))
|
||||
return EvalEarlyExitError{}
|
||||
|
||||
// Keep existing warnings, while converting errors to warnings.
|
||||
// This is not meant to be the normal path, so there no need to
|
||||
// make the errors pretty.
|
||||
var warnings tfdiags.Diagnostics
|
||||
for _, d := range diags {
|
||||
switch d.Severity() {
|
||||
case tfdiags.Warning:
|
||||
warnings = warnings.Append(d)
|
||||
case tfdiags.Error:
|
||||
desc := d.Description()
|
||||
warnings = warnings.Append(tfdiags.SimpleWarning(fmt.Sprintf("%s:%s", desc.Summary, desc.Detail)))
|
||||
}
|
||||
}
|
||||
|
||||
return warnings
|
||||
}
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
n.setValue(state, changes, val)
|
||||
|
||||
|
@ -309,7 +323,7 @@ func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) error {
|
|||
n.setValue(state, changes, val)
|
||||
}
|
||||
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// dag.GraphNodeDotter impl.
|
||||
|
@ -350,7 +364,7 @@ func (n *NodeDestroyableOutput) temporaryValue() bool {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeDestroyableOutput) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeDestroyableOutput) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
||||
state := ctx.State()
|
||||
if state == nil {
|
||||
return nil
|
||||
|
|
|
@ -81,11 +81,11 @@ func TestNodeApplyableOutputExecute_invalidDependsOn(t *testing.T) {
|
|||
})
|
||||
ctx.EvaluateExprResult = val
|
||||
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err == nil {
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("expected execute error, but there was none")
|
||||
}
|
||||
if got, want := err.Error(), "Invalid depends_on reference"; !strings.Contains(got, want) {
|
||||
if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) {
|
||||
t.Errorf("expected error to include %q, but was: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
@ -102,11 +102,11 @@ func TestNodeApplyableOutputExecute_sensitiveValueNotOutput(t *testing.T) {
|
|||
})
|
||||
ctx.EvaluateExprResult = val
|
||||
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err == nil {
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("expected execute error, but there was none")
|
||||
}
|
||||
if got, want := err.Error(), "Output refers to sensitive values"; !strings.Contains(got, want) {
|
||||
if got, want := diags.Err().Error(), "Output refers to sensitive values"; !strings.Contains(got, want) {
|
||||
t.Errorf("expected error to include %q, but was: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
@ -151,9 +151,9 @@ func TestNodeDestroyableOutputExecute(t *testing.T) {
|
|||
}
|
||||
node := NodeDestroyableOutput{Addr: outputAddr}
|
||||
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("Unexpected error: %s", diags.Err())
|
||||
}
|
||||
if state.OutputValue(outputAddr) != nil {
|
||||
t.Fatal("Unexpected outputs in state after removal")
|
||||
|
|
|
@ -20,36 +20,37 @@ var (
|
|||
)
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
_, err := ctx.InitProvider(n.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
provider, _, err := GetProvider(ctx, n.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
switch op {
|
||||
case walkValidate:
|
||||
return n.ValidateProvider(ctx, provider)
|
||||
return diags.Append(n.ValidateProvider(ctx, provider))
|
||||
case walkPlan, walkApply, walkDestroy:
|
||||
return n.ConfigureProvider(ctx, provider, false)
|
||||
return diags.Append(n.ConfigureProvider(ctx, provider, false))
|
||||
case walkImport:
|
||||
return n.ConfigureProvider(ctx, provider, true)
|
||||
return diags.Append(n.ConfigureProvider(ctx, provider, true))
|
||||
}
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
||||
func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider providers.Interface) error {
|
||||
var diags tfdiags.Diagnostics
|
||||
func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider providers.Interface) (diags tfdiags.Diagnostics) {
|
||||
|
||||
configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig())
|
||||
|
||||
resp := provider.GetSchema()
|
||||
diags = diags.Append(resp.Diagnostics)
|
||||
if diags.HasErrors() {
|
||||
return diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
configSchema := resp.Provider.Block
|
||||
|
@ -63,7 +64,7 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
|
|||
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
|
||||
diags = diags.Append(evalDiags)
|
||||
if evalDiags.HasErrors() {
|
||||
return diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
req := providers.PrepareProviderConfigRequest{
|
||||
|
@ -73,14 +74,13 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
|
|||
validateResp := provider.PrepareProviderConfig(req)
|
||||
diags = diags.Append(validateResp.Diagnostics)
|
||||
|
||||
return diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
// ConfigureProvider configures a provider that is already initialized and retrieved.
|
||||
// If verifyConfigIsKnown is true, ConfigureProvider will return an error if the
|
||||
// provider configVal is not wholly known and is meant only for use during import.
|
||||
func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider providers.Interface, verifyConfigIsKnown bool) error {
|
||||
var diags tfdiags.Diagnostics
|
||||
func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider providers.Interface, verifyConfigIsKnown bool) (diags tfdiags.Diagnostics) {
|
||||
config := n.ProviderConfig()
|
||||
|
||||
configBody := buildProviderConfig(ctx, n.Addr, config)
|
||||
|
@ -88,14 +88,14 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider prov
|
|||
resp := provider.GetSchema()
|
||||
diags = diags.Append(resp.Diagnostics)
|
||||
if diags.HasErrors() {
|
||||
return diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
configSchema := resp.Provider.Block
|
||||
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
|
||||
diags = diags.Append(evalDiags)
|
||||
if evalDiags.HasErrors() {
|
||||
return diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
if verifyConfigIsKnown && !configVal.IsWhollyKnown() {
|
||||
|
@ -105,11 +105,11 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider prov
|
|||
Detail: fmt.Sprintf("The configuration for %s depends on values that cannot be determined until apply.", n.Addr),
|
||||
Subject: &config.DeclRange,
|
||||
})
|
||||
return diags.ErrWithWarnings()
|
||||
return diags
|
||||
}
|
||||
|
||||
configDiags := ctx.ConfigureProvider(n.Addr, configVal)
|
||||
configDiags = configDiags.InConfigBody(configBody)
|
||||
|
||||
return configDiags.ErrWithWarnings()
|
||||
return configDiags
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package terraform
|
||||
|
||||
import "github.com/hashicorp/terraform/tfdiags"
|
||||
|
||||
// NodeEvalableProvider represents a provider during an "eval" walk.
|
||||
// This special provider node type just initializes a provider and
|
||||
// fetches its schema, without configuring it or otherwise interacting
|
||||
|
@ -8,8 +10,10 @@ type NodeEvalableProvider struct {
|
|||
*NodeAbstractProvider
|
||||
}
|
||||
|
||||
var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil)
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeEvalableProvider) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeEvalableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
_, err := ctx.InitProvider(n.Addr)
|
||||
return err
|
||||
return diags.Append(err)
|
||||
}
|
||||
|
|
|
@ -65,13 +65,13 @@ func TestNodeApplyableProviderExecute_unknownImport(t *testing.T) {
|
|||
ctx := &MockEvalContext{ProviderProvider: provider}
|
||||
ctx.installSimpleEval()
|
||||
|
||||
err := n.Execute(ctx, walkImport)
|
||||
if err == nil {
|
||||
diags := n.Execute(ctx, walkImport)
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("expected error, got success")
|
||||
}
|
||||
|
||||
detail := `Invalid provider configuration: The configuration for provider["registry.terraform.io/hashicorp/foo"] depends on values that cannot be determined until apply.`
|
||||
if got, want := err.Error(), detail; got != want {
|
||||
if got, want := diags.Err().Error(), detail; got != want {
|
||||
t.Errorf("wrong diagnostic detail\n got: %q\nwant: %q", got, want)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// NodeProvisioner represents a provider that has no associated operations.
|
||||
|
@ -39,6 +40,6 @@ func (n *NodeProvisioner) ProvisionerName() string {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable impl.
|
||||
func (n *NodeProvisioner) Execute(ctx EvalContext, op walkOperation) error {
|
||||
return ctx.InitProvisioner(n.NameValue)
|
||||
func (n *NodeProvisioner) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
return diags.Append(ctx.InitProvisioner(n.NameValue))
|
||||
}
|
||||
|
|
|
@ -305,8 +305,7 @@ func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotN
|
|||
// eval is the only change we get to set the resource "each mode" to list
|
||||
// in that case, allowing expression evaluation to see it as a zero-element list
|
||||
// rather than as not set at all.
|
||||
func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.AbsResource) error {
|
||||
var diags tfdiags.Diagnostics
|
||||
func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.AbsResource) (diags tfdiags.Diagnostics) {
|
||||
state := ctx.State()
|
||||
|
||||
// We'll record our expansion decision in the shared "expander" object
|
||||
|
@ -320,7 +319,7 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
|
|||
count, countDiags := evaluateCountExpression(n.Config.Count, ctx)
|
||||
diags = diags.Append(countDiags)
|
||||
if countDiags.HasErrors() {
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
state.SetResourceProvider(addr, n.ResolvedProvider)
|
||||
|
@ -330,7 +329,7 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
|
|||
forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx)
|
||||
diags = diags.Append(forEachDiags)
|
||||
if forEachDiags.HasErrors() {
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
// This method takes care of all of the business logic of updating this
|
||||
|
@ -343,7 +342,7 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
|
|||
expander.SetResourceSingle(addr.Module, n.Addr.Resource)
|
||||
}
|
||||
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
||||
// ReadResourceInstanceState reads the current object for a specific instance in
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
"github.com/hashicorp/terraform/lang"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// nodeExpandApplyableResource handles the first layer of resource
|
||||
|
@ -102,13 +103,12 @@ func (n *NodeApplyableResource) References() []*addrs.Reference {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeApplyableResource) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeApplyableResource) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
||||
if n.Config == nil {
|
||||
// Nothing to do, then.
|
||||
log.Printf("[TRACE] NodeApplyableResource: no configuration present for %s", n.Name())
|
||||
return nil
|
||||
}
|
||||
|
||||
err := n.writeResourceState(ctx, n.Addr)
|
||||
return err
|
||||
return n.writeResourceState(ctx, n.Addr)
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ func (n *NodeApplyableResourceInstance) AttachDependencies(deps []addrs.ConfigRe
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
if n.Config == nil {
|
||||
|
@ -110,7 +110,6 @@ func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperatio
|
|||
// https://github.com/hashicorp/terraform/issues/21258
|
||||
// To avoid an outright crash here, we'll instead return an explicit
|
||||
// error.
|
||||
var diags tfdiags.Diagnostics
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Resource node has no configuration attached",
|
||||
|
@ -119,7 +118,7 @@ func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperatio
|
|||
addr,
|
||||
),
|
||||
))
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
// Eval info is different depending on what kind of resource this is
|
||||
|
@ -133,21 +132,23 @@ func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperatio
|
|||
}
|
||||
}
|
||||
|
||||
func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) error {
|
||||
func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceInstanceAddr().Resource
|
||||
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
change, err := n.readDiff(ctx, providerSchema)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
// Stop early if we don't actually have a diff
|
||||
if change == nil {
|
||||
return EvalEarlyExitError{}
|
||||
return diags
|
||||
}
|
||||
|
||||
// In this particular call to EvalReadData we include our planned
|
||||
|
@ -166,9 +167,9 @@ func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
State: &state,
|
||||
},
|
||||
}
|
||||
_, err = readDataApply.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(readDataApply.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeState := &EvalWriteState{
|
||||
|
@ -177,9 +178,9 @@ func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
ProviderSchema: &providerSchema,
|
||||
State: &state,
|
||||
}
|
||||
_, err = writeState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeDiff := &EvalWriteDiff{
|
||||
|
@ -187,16 +188,16 @@ func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
ProviderSchema: &providerSchema,
|
||||
Change: nil,
|
||||
}
|
||||
_, err = writeDiff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeDiff.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
UpdateStateHook(ctx)
|
||||
return nil
|
||||
diags = diags.Append(UpdateStateHook(ctx))
|
||||
return diags
|
||||
}
|
||||
|
||||
func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext) error {
|
||||
func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
||||
// Declare a bunch of variables that are used for state during
|
||||
// evaluation. Most of this are written to by-address below.
|
||||
var state *states.ResourceInstanceObject
|
||||
|
@ -206,20 +207,22 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
|
||||
addr := n.ResourceInstanceAddr().Resource
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Get the saved diff for apply
|
||||
diffApply, err := n.readDiff(ctx, providerSchema)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// We don't want to do any destroys
|
||||
// (these are handled by NodeDestroyResourceInstance instead)
|
||||
if diffApply == nil || diffApply.Action == plans.Delete {
|
||||
return EvalEarlyExitError{}
|
||||
return diags
|
||||
}
|
||||
|
||||
destroy := (diffApply.Action == plans.Delete || diffApply.Action.IsReplace())
|
||||
|
@ -236,9 +239,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
ForceKey: n.PreallocatedDeposedKey,
|
||||
OutputKey: &deposedKey,
|
||||
}
|
||||
_, err = deposeState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(deposeState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,15 +252,16 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
|
||||
Output: &state,
|
||||
}
|
||||
_, err = readState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(readState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Get the saved diff
|
||||
diff, err := n.readDiff(ctx, providerSchema)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Make a new diff, in case we've learned new values in the state
|
||||
|
@ -274,9 +278,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
OutputChange: &diffApply,
|
||||
OutputState: &state,
|
||||
}
|
||||
_, err = evalDiff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalDiff.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Compare the diffs
|
||||
|
@ -287,9 +291,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
Planned: &diff,
|
||||
Actual: &diffApply,
|
||||
}
|
||||
_, err = checkPlannedChange.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(checkPlannedChange.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
readState = &EvalReadState{
|
||||
|
@ -299,9 +303,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
|
||||
Output: &state,
|
||||
}
|
||||
_, err = readState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(readState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
reduceDiff := &EvalReduceDiff{
|
||||
|
@ -310,16 +314,16 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
Destroy: false,
|
||||
OutChange: &diffApply,
|
||||
}
|
||||
_, err = reduceDiff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(reduceDiff.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalReduceDiff may have simplified our planned change
|
||||
// into a NoOp if it only requires destroying, since destroying
|
||||
// is handled by NodeDestroyResourceInstance.
|
||||
if diffApply == nil || diffApply.Action == plans.NoOp {
|
||||
return EvalEarlyExitError{}
|
||||
return diags
|
||||
}
|
||||
|
||||
evalApplyPre := &EvalApplyPre{
|
||||
|
@ -327,9 +331,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
State: &state,
|
||||
Change: &diffApply,
|
||||
}
|
||||
_, err = evalApplyPre.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalApplyPre.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
var applyError error
|
||||
|
@ -347,9 +351,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
CreateNew: &createNew,
|
||||
CreateBeforeDestroy: n.CreateBeforeDestroy(),
|
||||
}
|
||||
_, err = evalApply.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalApply.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// We clear the change out here so that future nodes don't see a change
|
||||
|
@ -359,9 +363,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
ProviderSchema: &providerSchema,
|
||||
Change: nil,
|
||||
}
|
||||
_, err = writeDiff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeDiff.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
evalMaybeTainted := &EvalMaybeTainted{
|
||||
|
@ -370,9 +374,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
Change: &diffApply,
|
||||
Error: &applyError,
|
||||
}
|
||||
_, err = evalMaybeTainted.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalMaybeTainted.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeState := &EvalWriteState{
|
||||
|
@ -382,9 +386,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
State: &state,
|
||||
Dependencies: &n.Dependencies,
|
||||
}
|
||||
_, err = writeState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
applyProvisioners := &EvalApplyProvisioners{
|
||||
|
@ -395,9 +399,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
Error: &applyError,
|
||||
When: configs.ProvisionerWhenCreate,
|
||||
}
|
||||
_, err = applyProvisioners.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(applyProvisioners.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
evalMaybeTainted = &EvalMaybeTainted{
|
||||
|
@ -406,9 +410,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
Change: &diffApply,
|
||||
Error: &applyError,
|
||||
}
|
||||
_, err = evalMaybeTainted.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalMaybeTainted.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeState = &EvalWriteState{
|
||||
|
@ -418,9 +422,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
State: &state,
|
||||
Dependencies: &n.Dependencies,
|
||||
}
|
||||
_, err = writeState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
if createBeforeDestroyEnabled && applyError != nil {
|
||||
|
@ -429,9 +433,9 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
PlannedChange: &diffApply,
|
||||
Key: &deposedKey,
|
||||
}
|
||||
_, err := maybeRestoreDesposedObject.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags := diags.Append(maybeRestoreDesposedObject.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -440,11 +444,11 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
State: &state,
|
||||
Error: &applyError,
|
||||
}
|
||||
_, err = applyPost.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(applyPost.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
UpdateStateHook(ctx)
|
||||
return nil
|
||||
diags = diags.Append(UpdateStateHook(ctx))
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -23,9 +23,9 @@ func TestNodeApplyableResourceExecute(t *testing.T) {
|
|||
},
|
||||
Addr: mustAbsResourceAddr("test_instance.foo"),
|
||||
}
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
if !state.Empty() {
|
||||
t.Fatalf("expected no state, got:\n %s", state.String())
|
||||
|
@ -48,9 +48,9 @@ func TestNodeApplyableResourceExecute(t *testing.T) {
|
|||
},
|
||||
Addr: mustAbsResourceAddr("test_instance.foo"),
|
||||
}
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
if state.Empty() {
|
||||
t.Fatal("expected resources in state, got empty state")
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
|
@ -122,7 +123,7 @@ func (n *NodeDestroyResourceInstance) References() []*addrs.Reference {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
// Get our state
|
||||
|
@ -137,13 +138,15 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
var provisionerErr error
|
||||
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
changeApply, err = n.readDiff(ctx, providerSchema)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
evalReduceDiff := &EvalReduceDiff{
|
||||
|
@ -152,25 +155,26 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
Destroy: true,
|
||||
OutChange: &changeApply,
|
||||
}
|
||||
_, err = evalReduceDiff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalReduceDiff.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalReduceDiff may have simplified our planned change
|
||||
// into a NoOp if it does not require destroying.
|
||||
if changeApply == nil || changeApply.Action == plans.NoOp {
|
||||
return EvalEarlyExitError{}
|
||||
return diags
|
||||
}
|
||||
|
||||
state, err = n.ReadResourceInstanceState(ctx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Exit early if the state object is null after reading the state
|
||||
if state == nil || state.Value.IsNull() {
|
||||
return EvalEarlyExitError{}
|
||||
return diags
|
||||
}
|
||||
|
||||
evalApplyPre := &EvalApplyPre{
|
||||
|
@ -178,9 +182,9 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
State: &state,
|
||||
Change: &changeApply,
|
||||
}
|
||||
_, err = evalApplyPre.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalApplyPre.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Run destroy provisioners if not tainted
|
||||
|
@ -192,9 +196,9 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
Error: &provisionerErr,
|
||||
When: configs.ProvisionerWhenDestroy,
|
||||
}
|
||||
_, err := evalApplyProvisioners.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalApplyProvisioners.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
if provisionerErr != nil {
|
||||
// If we have a provisioning error, then we just call
|
||||
|
@ -204,9 +208,9 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
State: &state,
|
||||
Error: &provisionerErr,
|
||||
}
|
||||
_, err = evalApplyPost.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalApplyPost.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,9 +230,9 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
Output: &state,
|
||||
Error: &provisionerErr,
|
||||
}
|
||||
_, err = evalApply.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalApply.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
evalWriteState := &EvalWriteState{
|
||||
|
@ -237,9 +241,9 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
ProviderSchema: &providerSchema,
|
||||
State: &state,
|
||||
}
|
||||
_, err = evalWriteState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalWriteState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
} else {
|
||||
log.Printf("[TRACE] NodeDestroyResourceInstance: removing state object for %s", n.Addr)
|
||||
|
@ -252,15 +256,11 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
|
|||
State: &state,
|
||||
Error: &provisionerErr,
|
||||
}
|
||||
_, err = evalApplyPost.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalApplyPost.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
err = UpdateStateHook(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
diags = diags.Append(UpdateStateHook(ctx))
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/hashicorp/terraform/dag"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// ConcreteResourceInstanceDeposedNodeFunc is a callback type used to convert
|
||||
|
@ -63,12 +64,13 @@ func (n *NodePlanDeposedResourceInstanceObject) References() []*addrs.Reference
|
|||
}
|
||||
|
||||
// GraphNodeEvalable impl.
|
||||
func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// During the plan walk we always produce a planned destroy change, because
|
||||
|
@ -83,9 +85,9 @@ func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walk
|
|||
Provider: &provider,
|
||||
ProviderSchema: &providerSchema,
|
||||
}
|
||||
_, err = readStateDeposed.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(readStateDeposed.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
diffDestroy := &EvalDiffDestroy{
|
||||
|
@ -95,9 +97,9 @@ func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walk
|
|||
State: &state,
|
||||
Output: &change,
|
||||
}
|
||||
_, err = diffDestroy.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(diffDestroy.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeDiff := &EvalWriteDiff{
|
||||
|
@ -106,12 +108,8 @@ func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walk
|
|||
ProviderSchema: &providerSchema,
|
||||
Change: &change,
|
||||
}
|
||||
_, err = writeDiff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
diags = diags.Append(writeDiff.Eval(ctx))
|
||||
return diags
|
||||
}
|
||||
|
||||
// NodeDestroyDeposedResourceInstanceObject represents deposed resource
|
||||
|
@ -181,7 +179,7 @@ func (n *NodeDestroyDeposedResourceInstanceObject) ModifyCreateBeforeDestroy(v b
|
|||
}
|
||||
|
||||
// GraphNodeExecutable impl.
|
||||
func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceInstanceAddr().Resource
|
||||
|
||||
var state *states.ResourceInstanceObject
|
||||
|
@ -189,8 +187,9 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w
|
|||
var applyError error
|
||||
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
readStateDeposed := &EvalReadStateDeposed{
|
||||
|
@ -200,9 +199,9 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w
|
|||
Provider: &provider,
|
||||
ProviderSchema: &providerSchema,
|
||||
}
|
||||
_, err = readStateDeposed.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(readStateDeposed.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
diffDestroy := &EvalDiffDestroy{
|
||||
|
@ -211,9 +210,9 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w
|
|||
State: &state,
|
||||
Output: &change,
|
||||
}
|
||||
_, err = diffDestroy.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(diffDestroy.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Call pre-apply hook
|
||||
|
@ -222,9 +221,9 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w
|
|||
State: &state,
|
||||
Change: &change,
|
||||
}
|
||||
_, err = applyPre.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(applyPre.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
apply := &EvalApply{
|
||||
|
@ -238,9 +237,9 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w
|
|||
Output: &state,
|
||||
Error: &applyError,
|
||||
}
|
||||
_, err = apply.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(apply.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Always write the resource back to the state deposed. If it
|
||||
|
@ -253,9 +252,9 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w
|
|||
ProviderSchema: &providerSchema,
|
||||
State: &state,
|
||||
}
|
||||
_, err = writeStateDeposed.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeStateDeposed.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
applyPost := &EvalApplyPost{
|
||||
|
@ -263,15 +262,16 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w
|
|||
State: &state,
|
||||
Error: &applyError,
|
||||
}
|
||||
_, err = applyPost.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(applyPost.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
if applyError != nil {
|
||||
return applyError
|
||||
diags = diags.Append(applyError)
|
||||
return diags
|
||||
}
|
||||
UpdateStateHook(ctx)
|
||||
return nil
|
||||
diags = diags.Append(UpdateStateHook(ctx))
|
||||
return diags
|
||||
}
|
||||
|
||||
// GraphNodeDeposer is an optional interface implemented by graph nodes that
|
||||
|
|
|
@ -178,15 +178,14 @@ func (n *NodePlannableResource) ModuleInstance() addrs.ModuleInstance {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodePlannableResource) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodePlannableResource) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
||||
if n.Config == nil {
|
||||
// Nothing to do, then.
|
||||
log.Printf("[TRACE] NodeApplyableResource: no configuration present for %s", n.Name())
|
||||
return nil
|
||||
}
|
||||
|
||||
err := n.writeResourceState(ctx, n.Addr)
|
||||
return err
|
||||
return n.writeResourceState(ctx, n.Addr)
|
||||
}
|
||||
|
||||
// GraphNodeDestroyerCBD
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// NodePlanDestroyableResourceInstance represents a resource that is ready
|
||||
|
@ -32,7 +33,7 @@ func (n *NodePlanDestroyableResourceInstance) DestroyAddr() *addrs.AbsResourceIn
|
|||
}
|
||||
|
||||
// GraphNodeEvalable
|
||||
func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
// Declare a bunch of variables that are used for state during
|
||||
|
@ -42,13 +43,15 @@ func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOp
|
|||
var state *states.ResourceInstanceObject
|
||||
|
||||
_, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
state, err = n.ReadResourceInstanceState(ctx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
diffDestroy := &EvalDiffDestroy{
|
||||
|
@ -57,14 +60,14 @@ func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOp
|
|||
State: &state,
|
||||
Output: &change,
|
||||
}
|
||||
_, err = diffDestroy.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(diffDestroy.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
err = n.checkPreventDestroy(change)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(n.checkPreventDestroy(change))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeDiff := &EvalWriteDiff{
|
||||
|
@ -72,6 +75,6 @@ func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOp
|
|||
ProviderSchema: &providerSchema,
|
||||
Change: &change,
|
||||
}
|
||||
_, err = writeDiff.Eval(ctx)
|
||||
return err
|
||||
diags = diags.Append(writeDiff.Eval(ctx))
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
)
|
||||
|
@ -30,7 +31,7 @@ var (
|
|||
)
|
||||
|
||||
// GraphNodeEvalable
|
||||
func (n *NodePlannableResourceInstance) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodePlannableResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
// Eval info is different depending on what kind of resource this is
|
||||
|
@ -44,7 +45,7 @@ func (n *NodePlannableResourceInstance) Execute(ctx EvalContext, op walkOperatio
|
|||
}
|
||||
}
|
||||
|
||||
func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) error {
|
||||
func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
||||
config := n.Config
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
|
@ -52,13 +53,15 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
var state *states.ResourceInstanceObject
|
||||
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
state, err = n.ReadResourceInstanceState(ctx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
validateSelfRef := &EvalValidateSelfRef{
|
||||
|
@ -66,9 +69,9 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
Config: config.Config,
|
||||
ProviderSchema: &providerSchema,
|
||||
}
|
||||
_, err = validateSelfRef.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(validateSelfRef.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
readDataPlan := &evalReadDataPlan{
|
||||
|
@ -84,9 +87,9 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
dependsOn: n.dependsOn,
|
||||
},
|
||||
}
|
||||
_, err = readDataPlan.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(readDataPlan.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// write the data source into both the refresh state and the
|
||||
|
@ -98,9 +101,9 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
State: &state,
|
||||
targetState: refreshState,
|
||||
}
|
||||
_, err = writeRefreshState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeRefreshState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeState := &EvalWriteState{
|
||||
|
@ -109,9 +112,9 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
ProviderSchema: &providerSchema,
|
||||
State: &state,
|
||||
}
|
||||
_, err = writeState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeDiff := &EvalWriteDiff{
|
||||
|
@ -119,11 +122,11 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) err
|
|||
ProviderSchema: &providerSchema,
|
||||
Change: &change,
|
||||
}
|
||||
_, err = writeDiff.Eval(ctx)
|
||||
return err
|
||||
diags = diags.Append(writeDiff.Eval(ctx))
|
||||
return diags
|
||||
}
|
||||
|
||||
func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext) error {
|
||||
func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
||||
config := n.Config
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
|
@ -132,8 +135,9 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
var instancePlanState *states.ResourceInstanceObject
|
||||
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
validateSelfRef := &EvalValidateSelfRef{
|
||||
|
@ -141,14 +145,15 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
Config: config.Config,
|
||||
ProviderSchema: &providerSchema,
|
||||
}
|
||||
_, err = validateSelfRef.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(validateSelfRef.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
instanceRefreshState, err = n.ReadResourceInstanceState(ctx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
refreshLifecycle := &EvalRefreshLifecycle{
|
||||
Addr: addr,
|
||||
|
@ -156,9 +161,9 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
State: &instanceRefreshState,
|
||||
ForceCreateBeforeDestroy: n.ForceCreateBeforeDestroy,
|
||||
}
|
||||
_, err = refreshLifecycle.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(refreshLifecycle.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Refresh, maybe
|
||||
|
@ -172,9 +177,9 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
State: &instanceRefreshState,
|
||||
Output: &instanceRefreshState,
|
||||
}
|
||||
_, err = refresh.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags := diags.Append(refresh.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeRefreshState := &EvalWriteState{
|
||||
|
@ -185,9 +190,9 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
targetState: refreshState,
|
||||
Dependencies: &n.Dependencies,
|
||||
}
|
||||
_, err = writeRefreshState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeRefreshState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,14 +209,14 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
OutputChange: &change,
|
||||
OutputState: &instancePlanState,
|
||||
}
|
||||
_, err = diff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(diff.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
err = n.checkPreventDestroy(change)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(n.checkPreventDestroy(change))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeState := &EvalWriteState{
|
||||
|
@ -220,9 +225,9 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
State: &instancePlanState,
|
||||
ProviderSchema: &providerSchema,
|
||||
}
|
||||
_, err = writeState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeDiff := &EvalWriteDiff{
|
||||
|
@ -230,6 +235,6 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
|||
ProviderSchema: &providerSchema,
|
||||
Change: &change,
|
||||
}
|
||||
_, err = writeDiff.Eval(ctx)
|
||||
return err
|
||||
diags = diags.Append(writeDiff.Eval(ctx))
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// NodePlannableResourceInstanceOrphan represents a resource that is "applyable":
|
||||
|
@ -33,7 +34,7 @@ func (n *NodePlannableResourceInstanceOrphan) Name() string {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
// Eval info is different depending on what kind of resource this is
|
||||
|
@ -47,7 +48,7 @@ func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOp
|
|||
}
|
||||
}
|
||||
|
||||
func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContext) error {
|
||||
func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContext) tfdiags.Diagnostics {
|
||||
// A data source that is no longer in the config is removed from the state
|
||||
log.Printf("[TRACE] NodePlannableResourceInstanceOrphan: removing state object for %s", n.Addr)
|
||||
state := ctx.RefreshState()
|
||||
|
@ -55,7 +56,7 @@ func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContex
|
|||
return nil
|
||||
}
|
||||
|
||||
func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalContext) error {
|
||||
func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceInstanceAddr()
|
||||
|
||||
// Declare a bunch of variables that are used for state during
|
||||
|
@ -64,13 +65,15 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
|||
var state *states.ResourceInstanceObject
|
||||
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
state, err = n.ReadResourceInstanceState(ctx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
if !n.skipRefresh {
|
||||
|
@ -89,9 +92,9 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
|||
State: &state,
|
||||
Output: &state,
|
||||
}
|
||||
_, err = refresh.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(refresh.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeRefreshState := &EvalWriteState{
|
||||
|
@ -101,9 +104,9 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
|||
State: &state,
|
||||
targetState: refreshState,
|
||||
}
|
||||
_, err = writeRefreshState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeRefreshState.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,14 +117,14 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
|||
Output: &change,
|
||||
OutputState: &state, // Will point to a nil state after this complete, signalling destroyed
|
||||
}
|
||||
_, err = diffDestroy.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(diffDestroy.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
err = n.checkPreventDestroy(change)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(n.checkPreventDestroy(change))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeDiff := &EvalWriteDiff{
|
||||
|
@ -129,9 +132,9 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
|||
ProviderSchema: &providerSchema,
|
||||
Change: &change,
|
||||
}
|
||||
_, err = writeDiff.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(writeDiff.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
writeState := &EvalWriteState{
|
||||
|
@ -140,9 +143,6 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
|||
ProviderSchema: &providerSchema,
|
||||
State: &state,
|
||||
}
|
||||
_, err = writeState.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
diags = diags.Append(writeState.Eval(ctx))
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -55,9 +55,9 @@ func TestNodeResourcePlanOrphanExecute(t *testing.T) {
|
|||
Addr: mustResourceInstanceAddr("test_object.foo"),
|
||||
},
|
||||
}
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
if !state.Empty() {
|
||||
t.Fatalf("expected empty state, got %s", state.String())
|
||||
|
|
|
@ -23,9 +23,9 @@ func TestNodePlannableResourceExecute(t *testing.T) {
|
|||
},
|
||||
Addr: mustAbsResourceAddr("test_instance.foo"),
|
||||
}
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
if !state.Empty() {
|
||||
t.Fatalf("expected no state, got:\n %s", state.String())
|
||||
|
@ -48,9 +48,9 @@ func TestNodePlannableResourceExecute(t *testing.T) {
|
|||
},
|
||||
Addr: mustAbsResourceAddr("test_instance.foo"),
|
||||
}
|
||||
err := node.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
if state.Empty() {
|
||||
t.Fatal("expected resources in state, got empty state")
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
|
@ -31,7 +32,7 @@ func (n *NodeValidatableResource) Path() addrs.ModuleInstance {
|
|||
}
|
||||
|
||||
// GraphNodeEvalable
|
||||
func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
addr := n.ResourceAddr()
|
||||
config := n.Config
|
||||
|
||||
|
@ -40,8 +41,9 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) err
|
|||
// passed to the EvalNodes.
|
||||
var configVal cty.Value
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
evalValidateResource := &EvalValidateResource{
|
||||
|
@ -52,9 +54,9 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) err
|
|||
Config: config,
|
||||
ConfigVal: &configVal,
|
||||
}
|
||||
err = evalValidateResource.Validate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalValidateResource.Validate(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
if managed := n.Config.Managed; managed != nil {
|
||||
|
@ -71,11 +73,13 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) err
|
|||
|
||||
provisioner := ctx.Provisioner(p.Type)
|
||||
if provisioner == nil {
|
||||
return fmt.Errorf("provisioner %s not initialized", p.Type)
|
||||
diags = diags.Append(fmt.Errorf("provisioner %s not initialized", p.Type))
|
||||
return diags
|
||||
}
|
||||
provisionerSchema := ctx.ProvisionerSchema(p.Type)
|
||||
if provisionerSchema == nil {
|
||||
return fmt.Errorf("provisioner %s not initialized", p.Type)
|
||||
diags = diags.Append(fmt.Errorf("provisioner %s not initialized", p.Type))
|
||||
return diags
|
||||
}
|
||||
|
||||
// Validate Provisioner Config
|
||||
|
@ -87,11 +91,11 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) err
|
|||
ResourceHasCount: hasCount,
|
||||
ResourceHasForEach: hasForEach,
|
||||
}
|
||||
err := validateProvisioner.Validate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(validateProvisioner.Validate(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// NodeRootVariable represents a root variable input.
|
||||
|
@ -36,7 +37,7 @@ func (n *NodeRootVariable) ReferenceableAddrs() []addrs.Referenceable {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable
|
||||
func (n *NodeRootVariable) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *NodeRootVariable) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
||||
// We don't actually need to _evaluate_ a root module variable, because
|
||||
// its value is always constant and already stashed away in our EvalContext.
|
||||
// However, we might need to run some user-defined validation rules against
|
||||
|
|
|
@ -17,9 +17,9 @@ func TestNodeRootVariableExecute(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
err := n.Execute(ctx, walkApply)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
diags := n.Execute(ctx, walkApply)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -116,25 +116,25 @@ func (n *graphNodeImportState) ModulePath() addrs.Module {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable impl.
|
||||
func (n *graphNodeImportState) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *graphNodeImportState) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
// Reset our states
|
||||
n.states = nil
|
||||
|
||||
provider, _, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// import state
|
||||
absAddr := n.Addr.Resource.Absolute(ctx.Path())
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Call pre-import hook
|
||||
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreImportState(absAddr, n.ID)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
resp := provider.ImportResourceState(providers.ImportResourceStateRequest{
|
||||
|
@ -143,7 +143,7 @@ func (n *graphNodeImportState) Execute(ctx EvalContext, op walkOperation) error
|
|||
})
|
||||
diags = diags.Append(resp.Diagnostics)
|
||||
if diags.HasErrors() {
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
imported := resp.ImportedResources
|
||||
|
@ -153,10 +153,10 @@ func (n *graphNodeImportState) Execute(ctx EvalContext, op walkOperation) error
|
|||
n.states = imported
|
||||
|
||||
// Call post-import hook
|
||||
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostImportState(absAddr, imported)
|
||||
})
|
||||
return err
|
||||
}))
|
||||
return diags
|
||||
}
|
||||
|
||||
// GraphNodeDynamicExpandable impl.
|
||||
|
@ -259,16 +259,18 @@ func (n *graphNodeImportStateSub) Path() addrs.ModuleInstance {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable impl.
|
||||
func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) error {
|
||||
func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
// If the Ephemeral type isn't set, then it is an error
|
||||
if n.State.TypeName == "" {
|
||||
return fmt.Errorf("import of %s didn't set type", n.TargetAddr.String())
|
||||
diags = diags.Append(fmt.Errorf("import of %s didn't set type", n.TargetAddr.String()))
|
||||
return diags
|
||||
}
|
||||
|
||||
state := n.State.AsInstanceObject()
|
||||
provider, providerSchema, err := GetProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(err)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// EvalRefresh
|
||||
|
@ -280,14 +282,13 @@ func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) err
|
|||
State: &state,
|
||||
Output: &state,
|
||||
}
|
||||
_, err = evalRefresh.Eval(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
diags = diags.Append(evalRefresh.Eval(ctx))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Verify the existance of the imported resource
|
||||
if state.Value.IsNull() {
|
||||
var diags tfdiags.Diagnostics
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Cannot import non-existent remote object",
|
||||
|
@ -296,7 +297,7 @@ func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) err
|
|||
n.TargetAddr.Resource.String(),
|
||||
),
|
||||
))
|
||||
return diags.Err()
|
||||
return diags
|
||||
}
|
||||
|
||||
//EvalWriteState
|
||||
|
@ -306,6 +307,6 @@ func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) err
|
|||
ProviderSchema: &providerSchema,
|
||||
State: &state,
|
||||
}
|
||||
_, err = evalWriteState.Eval(ctx)
|
||||
return err
|
||||
diags = diags.Append(evalWriteState.Eval(ctx))
|
||||
return diags
|
||||
}
|
||||
|
|
|
@ -41,9 +41,9 @@ func TestGraphNodeImportStateExecute(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
err := node.Execute(ctx, walkImport)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkImport)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("Unexpected error: %s", diags.Err())
|
||||
}
|
||||
|
||||
if len(node.states) != 1 {
|
||||
|
@ -93,9 +93,9 @@ func TestGraphNodeImportStateSubExecute(t *testing.T) {
|
|||
Module: addrs.RootModule,
|
||||
},
|
||||
}
|
||||
err := node.Execute(ctx, walkImport)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err.Error())
|
||||
diags := node.Execute(ctx, walkImport)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("Unexpected error: %s", diags.Err())
|
||||
}
|
||||
|
||||
// check for resource in state
|
||||
|
|
|
@ -449,6 +449,7 @@ type graphNodeCloseProvider struct {
|
|||
|
||||
var (
|
||||
_ GraphNodeCloseProvider = (*graphNodeCloseProvider)(nil)
|
||||
_ GraphNodeExecutable = (*graphNodeCloseProvider)(nil)
|
||||
)
|
||||
|
||||
func (n *graphNodeCloseProvider) Name() string {
|
||||
|
@ -461,8 +462,8 @@ func (n *graphNodeCloseProvider) ModulePath() addrs.Module {
|
|||
}
|
||||
|
||||
// GraphNodeExecutable impl.
|
||||
func (n *graphNodeCloseProvider) Execute(ctx EvalContext, op walkOperation) error {
|
||||
return ctx.CloseProvider(n.Addr)
|
||||
func (n *graphNodeCloseProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
return diags.Append(ctx.CloseProvider(n.Addr))
|
||||
}
|
||||
|
||||
// GraphNodeDependable impl.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// GraphNodeProvisioner is an interface that nodes that can be a provisioner
|
||||
|
@ -165,13 +166,15 @@ type graphNodeCloseProvisioner struct {
|
|||
ProvisionerNameValue string
|
||||
}
|
||||
|
||||
var _ GraphNodeExecutable = (*graphNodeCloseProvisioner)(nil)
|
||||
|
||||
func (n *graphNodeCloseProvisioner) Name() string {
|
||||
return fmt.Sprintf("provisioner.%s (close)", n.ProvisionerNameValue)
|
||||
}
|
||||
|
||||
// GraphNodeExecutable impl.
|
||||
func (n *graphNodeCloseProvisioner) Execute(ctx EvalContext, op walkOperation) error {
|
||||
return ctx.CloseProvisioner(n.ProvisionerNameValue)
|
||||
func (n *graphNodeCloseProvisioner) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
return diags.Append(ctx.CloseProvisioner(n.ProvisionerNameValue))
|
||||
}
|
||||
|
||||
func (n *graphNodeCloseProvisioner) CloseProvisionerName() string {
|
||||
|
|
Loading…
Reference in New Issue