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