7 "github.com/zclconf/go-cty/cty"
9 "github.com/hashicorp/terraform/addrs"
10 "github.com/hashicorp/terraform/providers"
11 "github.com/hashicorp/terraform/states"
12 "github.com/hashicorp/terraform/tfdiags"
15 // EvalRefresh is an EvalNode implementation that does a refresh for
17 type EvalRefresh struct {
18 Addr addrs.ResourceInstance
19 ProviderAddr addrs.AbsProviderConfig
20 Provider *providers.Interface
21 ProviderSchema **ProviderSchema
22 State **states.ResourceInstanceObject
23 Output **states.ResourceInstanceObject
27 func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
29 absAddr := n.Addr.Absolute(ctx.Path())
31 var diags tfdiags.Diagnostics
33 // If we have no state, we don't do any refreshing
35 log.Printf("[DEBUG] refresh: %s: no state, so not refreshing", n.Addr.Absolute(ctx.Path()))
36 return nil, diags.ErrWithWarnings()
39 schema, _ := (*n.ProviderSchema).SchemaForResourceAddr(n.Addr.ContainingResource())
41 // Should be caught during validation, so we don't bother with a pretty error here
42 return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
45 // Call pre-refresh hook
46 err := ctx.Hook(func(h Hook) (HookAction, error) {
47 return h.PreRefresh(absAddr, states.CurrentGen, state.Value)
50 return nil, diags.ErrWithWarnings()
54 priorVal := state.Value
55 req := providers.ReadResourceRequest{
56 TypeName: n.Addr.Resource.Type,
60 provider := *n.Provider
61 resp := provider.ReadResource(req)
62 diags = diags.Append(resp.Diagnostics)
63 if diags.HasErrors() {
64 return nil, diags.Err()
67 if resp.NewState == cty.NilVal {
68 // This ought not to happen in real cases since it's not possible to
69 // send NilVal over the plugin RPC channel, but it can come up in
70 // tests due to sloppy mocking.
71 panic("new state is cty.NilVal")
74 for _, err := range resp.NewState.Type().TestConformance(schema.ImpliedType()) {
75 diags = diags.Append(tfdiags.Sourceless(
77 "Provider produced invalid object",
79 "Provider %q planned an invalid value for %s during refresh: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
80 n.ProviderAddr.ProviderConfig.Type, absAddr, tfdiags.FormatError(err),
84 if diags.HasErrors() {
85 return nil, diags.Err()
88 newState := state.DeepCopy()
89 newState.Value = resp.NewState
91 // Call post-refresh hook
92 err = ctx.Hook(func(h Hook) (HookAction, error) {
93 return h.PostRefresh(absAddr, states.CurrentGen, priorVal, newState.Value)
103 return nil, diags.ErrWithWarnings()