mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-03-12 07:01:03 -04:00
Fixes #12174 You're allowed to refresh with a nil module (no configs) as long as you have state. However, if `-input=true` (default) then this would crash since the input attempts to read the configs. The API contract with `terraform.Context` says that the module tree must be non-nil and loaded. To do this for other commands we create an empty module tree. We do that here now.
96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
package local
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/hashicorp/errwrap"
|
|
"github.com/hashicorp/go-multierror"
|
|
"github.com/hashicorp/terraform/backend"
|
|
clistate "github.com/hashicorp/terraform/command/state"
|
|
"github.com/hashicorp/terraform/config/module"
|
|
"github.com/hashicorp/terraform/state"
|
|
)
|
|
|
|
func (b *Local) opRefresh(
|
|
ctx context.Context,
|
|
op *backend.Operation,
|
|
runningOp *backend.RunningOperation) {
|
|
// Check if our state exists if we're performing a refresh operation. We
|
|
// only do this if we're managing state with this backend.
|
|
if b.Backend == nil {
|
|
if _, err := os.Stat(b.StatePath); err != nil {
|
|
if os.IsNotExist(err) {
|
|
runningOp.Err = fmt.Errorf(
|
|
"The Terraform state file for your infrastructure does not\n"+
|
|
"exist. The 'refresh' command only works and only makes sense\n"+
|
|
"when there is existing state that Terraform is managing. Please\n"+
|
|
"double-check the value given below and try again. If you\n"+
|
|
"haven't created infrastructure with Terraform yet, use the\n"+
|
|
"'terraform apply' command.\n\n"+
|
|
"Path: %s",
|
|
b.StatePath)
|
|
return
|
|
}
|
|
|
|
runningOp.Err = fmt.Errorf(
|
|
"There was an error reading the Terraform state that is needed\n"+
|
|
"for refreshing. The path and error are shown below.\n\n"+
|
|
"Path: %s\n\nError: %s",
|
|
b.StatePath, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
// If we have no config module given to use, create an empty tree to
|
|
// avoid crashes when Terraform.Context is initialized.
|
|
if op.Module == nil {
|
|
op.Module = module.NewEmptyTree()
|
|
}
|
|
|
|
// Get our context
|
|
tfCtx, opState, err := b.context(op)
|
|
if err != nil {
|
|
runningOp.Err = err
|
|
return
|
|
}
|
|
|
|
if op.LockState {
|
|
lockInfo := state.NewLockInfo()
|
|
lockInfo.Operation = op.Type.String()
|
|
lockID, err := clistate.Lock(opState, lockInfo, b.CLI, b.Colorize())
|
|
if err != nil {
|
|
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
|
|
return
|
|
}
|
|
|
|
defer func() {
|
|
if err := clistate.Unlock(opState, lockID, b.CLI, b.Colorize()); err != nil {
|
|
runningOp.Err = multierror.Append(runningOp.Err, err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Set our state
|
|
runningOp.State = opState.State()
|
|
|
|
// Perform operation and write the resulting state to the running op
|
|
newState, err := tfCtx.Refresh()
|
|
runningOp.State = newState
|
|
if err != nil {
|
|
runningOp.Err = errwrap.Wrapf("Error refreshing state: {{err}}", err)
|
|
return
|
|
}
|
|
|
|
// Write and persist the state
|
|
if err := opState.WriteState(newState); err != nil {
|
|
runningOp.Err = errwrap.Wrapf("Error writing state: {{err}}", err)
|
|
return
|
|
}
|
|
if err := opState.PersistState(); err != nil {
|
|
runningOp.Err = errwrap.Wrapf("Error saving state: {{err}}", err)
|
|
return
|
|
}
|
|
}
|