opentofu/terraform/eval_refresh.go
James Bardin dcab82e897 send and receive Private through ReadResource
Send Private data blob through ReadResource as well. This will allow for
extra flexibility for future providers that may want to pass data out of
band through to their resource Read functions.
2019-06-03 18:08:26 -04:00

107 lines
2.9 KiB
Go

package terraform
import (
"fmt"
"log"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/tfdiags"
)
// EvalRefresh is an EvalNode implementation that does a refresh for
// a resource.
type EvalRefresh struct {
Addr addrs.ResourceInstance
ProviderAddr addrs.AbsProviderConfig
Provider *providers.Interface
ProviderSchema **ProviderSchema
State **states.ResourceInstanceObject
Output **states.ResourceInstanceObject
}
// TODO: test
func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
state := *n.State
absAddr := n.Addr.Absolute(ctx.Path())
var diags tfdiags.Diagnostics
// 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()
}
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)
}
// Call pre-refresh hook
err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PreRefresh(absAddr, states.CurrentGen, state.Value)
})
if err != nil {
return nil, diags.ErrWithWarnings()
}
// Refresh!
priorVal := state.Value
req := providers.ReadResourceRequest{
TypeName: n.Addr.Resource.Type,
PriorState: priorVal,
Private: state.Private,
}
provider := *n.Provider
resp := provider.ReadResource(req)
diags = diags.Append(resp.Diagnostics)
if diags.HasErrors() {
return nil, diags.Err()
}
if resp.NewState == cty.NilVal {
// This ought not to happen in real cases since it's not possible to
// send NilVal over the plugin RPC channel, but it can come up in
// tests due to sloppy mocking.
panic("new state is cty.NilVal")
}
for _, err := range resp.NewState.Type().TestConformance(schema.ImpliedType()) {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider produced invalid object",
fmt.Sprintf(
"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.",
n.ProviderAddr.ProviderConfig.Type, absAddr, tfdiags.FormatError(err),
),
))
}
if diags.HasErrors() {
return nil, diags.Err()
}
newState := state.DeepCopy()
newState.Value = resp.NewState
newState.Private = resp.Private
// Call post-refresh hook
err = ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostRefresh(absAddr, states.CurrentGen, priorVal, newState.Value)
})
if err != nil {
return nil, err
}
if n.Output != nil {
*n.Output = newState
}
return nil, diags.ErrWithWarnings()
}