github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/command/state_meta.go (about) 1 package command 2 3 import ( 4 "errors" 5 "fmt" 6 "time" 7 8 backendlocal "github.com/hashicorp/terraform/backend/local" 9 "github.com/hashicorp/terraform/state" 10 "github.com/hashicorp/terraform/terraform" 11 ) 12 13 // StateMeta is the meta struct that should be embedded in state subcommands. 14 type StateMeta struct { 15 Meta 16 } 17 18 // State returns the state for this meta. This gets the appropriate state from 19 // the backend, but changes the way that backups are done. This configures 20 // backups to be timestamped rather than just the original state path plus a 21 // backup path. 22 func (c *StateMeta) State() (state.State, error) { 23 var realState state.State 24 backupPath := c.backupPath 25 stateOutPath := c.statePath 26 27 // use the specified state 28 if c.statePath != "" { 29 realState = &state.LocalState{ 30 Path: c.statePath, 31 } 32 } else { 33 // Load the backend 34 b, err := c.Backend(nil) 35 if err != nil { 36 return nil, err 37 } 38 39 env := c.Workspace() 40 // Get the state 41 s, err := b.State(env) 42 if err != nil { 43 return nil, err 44 } 45 46 // Get a local backend 47 localRaw, err := c.Backend(&BackendOpts{ForceLocal: true}) 48 if err != nil { 49 // This should never fail 50 panic(err) 51 } 52 localB := localRaw.(*backendlocal.Local) 53 _, stateOutPath, _ = localB.StatePaths(env) 54 if err != nil { 55 return nil, err 56 } 57 58 realState = s 59 } 60 61 // We always backup state commands, so set the back if none was specified 62 // (the default is "-", but some tests bypass the flag parsing). 63 if backupPath == "-" || backupPath == "" { 64 // Determine the backup path. stateOutPath is set to the resulting 65 // file where state is written (cached in the case of remote state) 66 backupPath = fmt.Sprintf( 67 "%s.%d%s", 68 stateOutPath, 69 time.Now().UTC().Unix(), 70 DefaultBackupExtension) 71 } 72 73 // Wrap it for backups 74 realState = &state.BackupState{ 75 Real: realState, 76 Path: backupPath, 77 } 78 79 return realState, nil 80 } 81 82 // filterInstance filters a single instance out of filter results. 83 func (c *StateMeta) filterInstance(rs []*terraform.StateFilterResult) (*terraform.StateFilterResult, error) { 84 var result *terraform.StateFilterResult 85 for _, r := range rs { 86 if _, ok := r.Value.(*terraform.InstanceState); !ok { 87 continue 88 } 89 90 if result != nil { 91 return nil, errors.New(errStateMultiple) 92 } 93 94 result = r 95 } 96 97 return result, nil 98 } 99 100 const errStateMultiple = `Multiple instances found for the given pattern! 101 102 This command requires that the pattern match exactly one instance 103 of a resource. To view the matched instances, use "terraform state list". 104 Please modify the pattern to match only a single instance.`