diff --git a/installer/server/terraform.go b/installer/server/terraform.go index 5a5260e6b8..6e27cefa5f 100644 --- a/installer/server/terraform.go +++ b/installer/server/terraform.go @@ -5,8 +5,10 @@ import ( "fmt" "io/ioutil" "net/http" + "path/filepath" "strconv" "strings" + "time" "golang.org/x/crypto/bcrypt" "golang.org/x/net/context" @@ -17,6 +19,7 @@ import ( "github.com/coreos/tectonic-installer/installer/server/ctxh" "github.com/coreos/tectonic-installer/installer/server/defaults" "github.com/coreos/tectonic-installer/installer/server/terraform" + "github.com/kardianos/osext" ) func newAWSTerraformVars(c *TectonicAWSCluster) ([]asset.Asset, error) { @@ -339,8 +342,20 @@ func terraformDestroyHandler(sessionProvider sessions.Store) ctxh.ContextHandler // newExecutorFromApplyHandlerInput creates a new Executor based on the given // TerraformApplyHandlerInput. func newExecutorFromApplyHandlerInput(input *TerraformApplyHandlerInput) (*terraform.Executor, *ctxh.AppError) { + // Construct the path where the Executor should run based on the the cluster + // name and current's binary path. + binaryPath, err := osext.ExecutableFolder() + if err != nil { + return nil, ctxh.NewAppError(err, fmt.Sprintf("Could not determine executable's folder: %v", err.Error()), http.StatusInternalServerError) + } + clusterName := input.Variables["tectonic_cluster_name"].(string) + if len(clusterName) == 0 { + return nil, ctxh.NewAppError(err, "Tectonic cluster name not provided", http.StatusBadRequest) + } + exPath := filepath.Join(binaryPath, "clusters", clusterName+time.Now().Format("_2006-01-02_15-04-05")) + // Create a new Executor. - ex, err := terraform.NewExecutor() + ex, err := terraform.NewExecutor(exPath) if err != nil { return nil, ctxh.NewAppError(err, fmt.Sprintf("Could not create TerraForm executor: %v", err.Error()), http.StatusInternalServerError) } @@ -411,7 +426,7 @@ func restoreExecutionFromSession(req *http.Request, sessionProvider sessions.Sto if !ok { return nil, nil, -1, ctxh.NewAppError(err, "Could not find terraform_id in session. Run terraform apply first.", http.StatusNotFound) } - ex, err := terraform.NewExecutorFromPath(executionPath.(string)) + ex, err := terraform.NewExecutor(executionPath.(string)) if err != nil { return nil, nil, -1, ctxh.NewAppError(err, "could not create TerraForm executor", http.StatusInternalServerError) } diff --git a/installer/server/terraform/executor.go b/installer/server/terraform/executor.go index 5b70789493..cf6d61b85d 100644 --- a/installer/server/terraform/executor.go +++ b/installer/server/terraform/executor.go @@ -80,32 +80,13 @@ type Executor struct { } // NewExecutor initializes a new Executor. -func NewExecutor() (*Executor, error) { - // Create a temporary folder in which the new Executor can run. - executionPath, err := ioutil.TempDir(os.TempDir(), "tectonic") - if err != nil { - return nil, err - } - - // Create an executor in that path. - ex, err := NewExecutorFromPath(executionPath) - if err != nil { - os.RemoveAll(executionPath) - return nil, err - } - - return ex, err -} - -// NewExecutorFromPath creates an Executor from an existing path. -func NewExecutorFromPath(executionPath string) (*Executor, error) { - var err error - +func NewExecutor(executionPath string) (*Executor, error) { ex := new(Executor) ex.executionPath = executionPath - // Create the folder in which the logs will be stored, if not existing. - os.Mkdir(filepath.Join(ex.executionPath, logsFolderName), 0770) + // Create the folder in which the executor, and its logs will be stored, + // if not existing. + os.MkdirAll(filepath.Join(ex.executionPath, logsFolderName), 0770) // Create a Executor CLI configuration file, that contains the list of // vendored providers/provisioners. diff --git a/installer/server/terraform/executor_test.go b/installer/server/terraform/executor_test.go index ebf012b220..e36143a91b 100644 --- a/installer/server/terraform/executor_test.go +++ b/installer/server/terraform/executor_test.go @@ -52,8 +52,14 @@ func TestMain(m *testing.M) { // worked (State/Status), and then create a new executor at the path of the // existing one and verify the state is shared. func TestExecutorSimple(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "tectonic") + if err != nil { + t.Logf("Failed to create temporary directory: %s", err) + t.FailNow() + } + // Create an executor. - ex, err := NewExecutor() + ex, err := NewExecutor(tmpDir) if err == ErrBinaryNotFound { t.Skip("TerraForm not found, skipping") return @@ -98,7 +104,7 @@ func TestExecutorSimple(t *testing.T) { assert.NotZero(t, len(outputBytes)) // Creates a new executor at the same existing one. - ex2, err := NewExecutorFromPath(ex.WorkingDirectory()) + ex2, err := NewExecutor(ex.WorkingDirectory()) assert.Nil(t, err) assert.NotNil(t, ex2) @@ -111,8 +117,14 @@ func TestExecutorSimple(t *testing.T) { // TestExecutorMissingVar executes TerraForm apply with missing variables and // ensures it failed. func TestExecutorMissingVar(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "tectonic") + if err != nil { + t.Logf("Failed to create temporary directory: %s", err) + t.FailNow() + } + // Create an executor. - ex, err := NewExecutor() + ex, err := NewExecutor(tmpDir) if err == ErrBinaryNotFound { t.Skip("TerraForm not found, skipping") return @@ -135,7 +147,7 @@ func TestExecutorMissingVar(t *testing.T) { // Wait for its termination. select { case <-done: - case <-time.After(1 * time.Second): + case <-time.After(10 * time.Second): assert.FailNow(t, "TerraForm apply timed out") }