Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Commit 4ec63bc

Browse files
committed
command: deal with plan states
1 parent 89d3a10 commit 4ec63bc

3 files changed

Lines changed: 104 additions & 40 deletions

File tree

command/meta.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"flag"
66
"fmt"
77
"io"
8-
"log"
98
"os"
109
"path/filepath"
1110

@@ -41,11 +40,6 @@ type Meta struct {
4140
color bool
4241
oldUi cli.Ui
4342

44-
// useRemoteState is enabled if we are using remote state storage
45-
// This is set when the context is loaded if we read from a remote
46-
// enabled state file.
47-
useRemoteState bool
48-
4943
// statePath is the path to the state file. If this is empty, then
5044
// no state will be loaded. It is also okay for this to be a path to
5145
// a file that doesn't exist; it is assumed that this means that there
@@ -101,14 +95,16 @@ func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) {
10195
plan, err := terraform.ReadPlan(f)
10296
f.Close()
10397
if err == nil {
104-
// Check if remote state is enabled, but do not refresh.
105-
// Since a plan is supposed to lock-in the changes, we do not
106-
// attempt a state refresh.
107-
if plan != nil && plan.State != nil && plan.State.Remote != nil && plan.State.Remote.Type != "" {
108-
log.Printf("[INFO] Enabling remote state from plan")
109-
m.useRemoteState = true
98+
// Setup our state
99+
state, statePath, err := StateFromPlan(m.statePath, plan)
100+
if err != nil {
101+
return nil, false, fmt.Errorf("Error loading plan: %s", err)
110102
}
111103

104+
// Set our state
105+
m.state = state
106+
m.stateOutPath = statePath
107+
112108
if len(m.variables) > 0 {
113109
return nil, false, fmt.Errorf(
114110
"You can't set variables with the '-var' or '-var-file' flag\n" +

command/state.go

Lines changed: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/hashicorp/errwrap"
99
"github.com/hashicorp/terraform/state"
1010
"github.com/hashicorp/terraform/state/remote"
11+
"github.com/hashicorp/terraform/terraform"
1112
)
1213

1314
// State returns the proper state.State implementation to represent the
@@ -24,7 +25,7 @@ func State(localPath string) (state.State, string, error) {
2425
remoteCachePath := filepath.Join(DefaultDataDir, DefaultStateFilename)
2526
if _, err := os.Stat(remoteCachePath); err == nil {
2627
// We have a remote state, initialize that.
27-
result, err = remoteState(remoteCachePath)
28+
result, err = remoteStateFromPath(remoteCachePath)
2829
if err != nil {
2930
return nil, "", err
3031
}
@@ -62,60 +63,112 @@ func State(localPath string) (state.State, string, error) {
6263
resultPath = localPath
6364
}
6465

66+
// If we have a result, make sure to back it up
67+
if result != nil {
68+
result = &state.BackupState{
69+
Real: result,
70+
Path: resultPath + DefaultBackupExtention,
71+
}
72+
}
73+
6574
// Return whatever state we have
6675
return result, resultPath, nil
6776
}
6877

69-
func remoteState(path string) (state.State, error) {
70-
// First create the local state for the path
71-
local := &state.LocalState{Path: path}
72-
if err := local.RefreshState(); err != nil {
73-
return nil, err
78+
// StateFromPlan gets our state from the plan.
79+
func StateFromPlan(
80+
localPath string, plan *terraform.Plan) (state.State, string, error) {
81+
var result state.State
82+
resultPath := localPath
83+
if plan != nil && plan.State != nil &&
84+
plan.State.Remote != nil && plan.State.Remote.Type != "" {
85+
var err error
86+
87+
// It looks like we have a remote state in the plan, so
88+
// we have to initialize that.
89+
resultPath = filepath.Join(DefaultDataDir, DefaultStateFilename)
90+
result, err = remoteState(plan.State, resultPath, false)
91+
if err != nil {
92+
return nil, "", err
93+
}
7494
}
75-
localState := local.State()
7695

96+
if result == nil {
97+
local := &state.LocalState{Path: resultPath}
98+
local.SetState(plan.State)
99+
result = local
100+
}
101+
102+
// If we have a result, make sure to back it up
103+
result = &state.BackupState{
104+
Real: result,
105+
Path: resultPath + DefaultBackupExtention,
106+
}
107+
108+
return result, resultPath, nil
109+
}
110+
111+
func remoteState(
112+
local *terraform.State,
113+
localPath string, refresh bool) (state.State, error) {
77114
// If there is no remote settings, it is an error
78-
if localState.Remote == nil {
115+
if local.Remote == nil {
79116
return nil, fmt.Errorf("Remote state cache has no remote info")
80117
}
81118

82119
// Initialize the remote client based on the local state
83-
client, err := remote.NewClient(localState.Remote.Type, localState.Remote.Config)
120+
client, err := remote.NewClient(local.Remote.Type, local.Remote.Config)
84121
if err != nil {
85122
return nil, errwrap.Wrapf(fmt.Sprintf(
86123
"Error initializing remote driver '%s': {{err}}",
87-
localState.Remote.Type), err)
124+
local.Remote.Type), err)
88125
}
89126

90127
// Create the remote client
91128
durable := &remote.State{Client: client}
92129

93130
// Create the cached client
94131
cache := &state.CacheState{
95-
Cache: local,
132+
Cache: &state.LocalState{Path: localPath},
96133
Durable: durable,
97134
}
98135

99-
// Refresh the cache
100-
if err := cache.RefreshState(); err != nil {
101-
return nil, errwrap.Wrapf(
102-
"Error reloading remote state: {{err}}", err)
103-
}
104-
switch cache.RefreshResult() {
105-
case state.CacheRefreshNoop:
106-
case state.CacheRefreshInit:
107-
case state.CacheRefreshLocalNewer:
108-
case state.CacheRefreshUpdateLocal:
109-
// Write our local state out to the durable storage to start.
110-
if err := cache.WriteState(localState); err != nil {
111-
return nil, errwrap.Wrapf("Error preparing remote state: {{err}}", err)
136+
if refresh {
137+
// Refresh the cache
138+
if err := cache.RefreshState(); err != nil {
139+
return nil, errwrap.Wrapf(
140+
"Error reloading remote state: {{err}}", err)
112141
}
113-
if err := cache.PersistState(); err != nil {
114-
return nil, errwrap.Wrapf("Error preparing remote state: {{err}}", err)
142+
switch cache.RefreshResult() {
143+
case state.CacheRefreshNoop:
144+
case state.CacheRefreshInit:
145+
case state.CacheRefreshLocalNewer:
146+
case state.CacheRefreshUpdateLocal:
147+
// Write our local state out to the durable storage to start.
148+
if err := cache.WriteState(local); err != nil {
149+
return nil, errwrap.Wrapf(
150+
"Error preparing remote state: {{err}}", err)
151+
}
152+
if err := cache.PersistState(); err != nil {
153+
return nil, errwrap.Wrapf(
154+
"Error preparing remote state: {{err}}", err)
155+
}
156+
default:
157+
return nil, errwrap.Wrapf(
158+
"Error initilizing remote state: {{err}}", err)
115159
}
116-
default:
117-
return nil, errwrap.Wrapf("Error initilizing remote state: {{err}}", err)
118160
}
119161

120162
return cache, nil
121163
}
164+
165+
func remoteStateFromPath(path string) (state.State, error) {
166+
// First create the local state for the path
167+
local := &state.LocalState{Path: path}
168+
if err := local.RefreshState(); err != nil {
169+
return nil, err
170+
}
171+
localState := local.State()
172+
173+
return remoteState(localState, path, true)
174+
}

state/local.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ type LocalState struct {
1818
written bool
1919
}
2020

21+
// SetState will force a specific state in-memory for this local state.
22+
func (s *LocalState) SetState(state *terraform.State) {
23+
s.state = state
24+
}
25+
2126
// StateReader impl.
2227
func (s *LocalState) State() *terraform.State {
2328
return s.state
@@ -34,6 +39,16 @@ func (s *LocalState) WriteState(state *terraform.State) error {
3439
path = s.Path
3540
}
3641

42+
// If we don't have any state, we actually delete the file if it exists
43+
if state == nil {
44+
err := os.Remove(path)
45+
if err != nil && os.IsNotExist(err) {
46+
return nil
47+
}
48+
49+
return err
50+
}
51+
3752
f, err := os.Create(path)
3853
if err != nil {
3954
return err

0 commit comments

Comments
 (0)