From 9a692d45d8a7c890472d7a2aa420acadfc5c8522 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Fri, 18 Oct 2019 16:02:05 -0700 Subject: [PATCH] projects: Force local state storage for now For the sake of prototyping real operations, for now we'll just force all workspaces to use local state files in a prototype-specific directory. Eventually we should make this customizable using either state_storage or remote configuration, but we don't have the necessary remote client APIs for that yet (existing packages are built around the old backend model) and this temporary solution allows for some forward progress without significant refactoring of the state storage mechanisms. --- projects/workspaces.go | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/projects/workspaces.go b/projects/workspaces.go index 59942460a4..ee83eb56e1 100644 --- a/projects/workspaces.go +++ b/projects/workspaces.go @@ -3,6 +3,8 @@ package projects import ( "fmt" "log" + "os" + "path/filepath" "sort" "github.com/hashicorp/hcl/v2" @@ -293,12 +295,25 @@ func (w *Workspace) InputVariables() map[addrs.InputVariable]cty.Value { // server identified in the configuration. func (w *Workspace) StateMgr() (statemgr.Full, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "StateMgr not yet implemented", - "Workspace.StateMgr isn't implemented yet", - )) - return nil, diags + + // FIXME: For initial prototyping we're forcing local state at fixed + // paths on disk. Eventually this should respect the "remote" or + // "state_storage" settings in the workspace configuration. + + stateDir := filepath.Join(w.project.config.ProjectRoot, ".terraform", "workspaces2-prototype-state") + stateFilePath := filepath.Join(stateDir, w.addr.StringCompact()+".tfstate") + + err := os.MkdirAll(stateDir, os.ModePerm) + if err != nil { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Can't create local state directory", + fmt.Sprintf("Error creating %s: %s.", stateDir, err), + )) + return nil, diags + } + + return statemgr.NewFilesystem(stateFilePath), nil } // LatestOutputValues returns the output values recorded at the end of the @@ -331,6 +346,15 @@ func (w *Workspace) LatestOutputValues() (map[addrs.OutputValue]cty.Value, tfdia } state := stateMgr.State() + if state == nil { + // FIXME: In order to produce an error message when workspaces are + // established in the wrong order, the caller will need some way to + // distinguish between no snapshots yet at all (state == nil) and + // a snapshot without any outputs. For now these are indistinguishable, + // so a reference to a workspace not yet established will just produce + // a useless downstream error about the output not being present. + return nil, diags + } raw := state.RootModule().OutputValues ret := make(map[addrs.OutputValue]cty.Value, len(raw)) for k, v := range raw {