From 2bfcdbbd08f5b832dde9bc55ef3a4c772c462e15 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 2 Jun 2017 16:13:11 -0400 Subject: [PATCH] change init args to remove source copy When init was modified in 0.9 to initialize a terraform working directory, the legacy behavior was kept to copy or fetch module sources. This left the init command without the ability that the plan and apply commands have to target a specific directory for the operation. This commit removes the legacy behavior altogether, and allows init to target a directory for initialization, bringing it into parity with plan and apply. If one want to copy a module to the target or current directory, that will have to be done manually before calling init. We can later reintroduce fetching modules with init without breaking this new behavior, by adding the source as an optional second argument. The unit tests testing the copying of sources with init have been removed, as well as some out of date (and commented out) init tests regarding remote states. --- command/apply_test.go | 67 ---------- command/init.go | 64 +-------- command/init_test.go | 297 ++---------------------------------------- 3 files changed, 17 insertions(+), 411 deletions(-) diff --git a/command/apply_test.go b/command/apply_test.go index 0937eee079..88383232c2 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -378,73 +378,6 @@ func TestApply_error(t *testing.T) { } } -func TestApply_init(t *testing.T) { - // Change to the temporary directory - cwd, err := os.Getwd() - if err != nil { - t.Fatalf("err: %s", err) - } - dir := tempDir(t) - if err := os.MkdirAll(dir, 0755); err != nil { - t.Fatalf("err: %s", err) - } - if err := os.Chdir(dir); err != nil { - t.Fatalf("err: %s", err) - } - defer os.Chdir(cwd) - - // Create the test fixtures - statePath := testTempFile(t) - ln := testHttpServer(t) - defer ln.Close() - - // Initialize the command - p := testProvider() - ui := new(cli.MockUi) - c := &ApplyCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(p), - Ui: ui, - }, - } - - // Build the URL to the init - var u url.URL - u.Scheme = "http" - u.Host = ln.Addr().String() - u.Path = "/header" - - args := []string{ - "-state", statePath, - u.String(), - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) - } - - if _, err := os.Stat("hello.tf"); err != nil { - t.Fatalf("err: %s", err) - } - - if _, err := os.Stat(statePath); err != nil { - t.Fatalf("err: %s", err) - } - - f, err := os.Open(statePath) - if err != nil { - t.Fatalf("err: %s", err) - } - defer f.Close() - - state, err := terraform.ReadState(f) - if err != nil { - t.Fatalf("err: %s", err) - } - if state == nil { - t.Fatal("state should not be nil") - } -} - func TestApply_input(t *testing.T) { // Disable test mode so input would be asked test = false diff --git a/command/init.go b/command/init.go index 7b0ed1896b..8cfc224f11 100644 --- a/command/init.go +++ b/command/init.go @@ -8,7 +8,6 @@ import ( "sort" "strings" - getter "github.com/hashicorp/go-getter" multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/config" @@ -58,8 +57,8 @@ func (c *InitCommand) Run(args []string) int { // Validate the arg count args = cmdFlags.Args() - if len(args) > 2 { - c.Ui.Error("The init command expects at most two arguments.\n") + if len(args) > 1 { + c.Ui.Error("The init command expects at most one argument.\n") cmdFlags.Usage() return 1 } @@ -73,21 +72,10 @@ func (c *InitCommand) Run(args []string) int { } // Get the path and source module to copy - var path string - var source string - switch len(args) { - case 0: - path = pwd - case 1: - path = pwd - source = args[0] - case 2: - source = args[0] - path = args[1] - default: - panic("assertion failed on arg count") + path := pwd + if len(args) == 1 { + path = args[0] } - // Set the state out path to be the path requested for the module // to be copied. This ensures any remote states gets setup in the // proper directory. @@ -97,20 +85,6 @@ func (c *InitCommand) Run(args []string) int { // to output a newline before the success message var header bool - // If we have a source, copy it - if source != "" { - c.Ui.Output(c.Colorize().Color(fmt.Sprintf( - "[reset][bold]"+ - "Initializing configuration from: %q...", source))) - if err := c.copySource(path, source, pwd); err != nil { - c.Ui.Error(fmt.Sprintf( - "Error copying source: %s", err)) - return 1 - } - - header = true - } - // If our directory is empty, then we're done. We can't get or setup // the backend with an empty directory. if empty, err := config.IsEmptyDir(path); err != nil { @@ -302,27 +276,9 @@ func (c *InitCommand) getProviders(path string, state *terraform.State) error { return nil } -func (c *InitCommand) copySource(dst, src, pwd string) error { - // Verify the directory is empty - if empty, err := config.IsEmptyDir(dst); err != nil { - return fmt.Errorf("Error checking on destination path: %s", err) - } else if !empty { - return fmt.Errorf(strings.TrimSpace(errInitCopyNotEmpty)) - } - - // Detect - source, err := getter.Detect(src, pwd, getter.Detectors) - if err != nil { - return fmt.Errorf("Error with module source: %s", err) - } - - // Get it! - return module.GetCopy(dst, source) -} - func (c *InitCommand) Help() string { helpText := ` -Usage: terraform init [options] [SOURCE] [PATH] +Usage: terraform init [options] [DIR] Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. @@ -340,14 +296,6 @@ Usage: terraform init [options] [SOURCE] [PATH] If no arguments are given, the configuration in this working directory is initialized. - If one or two arguments are given, the first is a SOURCE of a module to - download to the second argument PATH. After downloading the module to PATH, - the configuration will be initialized as if this command were called pointing - only to that PATH. PATH must be empty of any Terraform files. Any - conflicting non-Terraform files will be overwritten. The module download - is a copy. If you're downloading a module from Git, it will not preserve - Git history. - Options: -backend=true Configure the backend for this configuration. diff --git a/command/init_test.go b/command/init_test.go index 9500a73f4f..816a06fd45 100644 --- a/command/init_test.go +++ b/command/init_test.go @@ -14,66 +14,6 @@ import ( "github.com/mitchellh/cli" ) -func TestInit(t *testing.T) { - dir := tempDir(t) - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - testFixturePath("init"), - dir, - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) - } - - if _, err := os.Stat(filepath.Join(dir, "hello.tf")); err != nil { - t.Fatalf("err: %s", err) - } -} - -func TestInit_cwd(t *testing.T) { - dir := tempDir(t) - if err := os.MkdirAll(dir, 0755); err != nil { - t.Fatalf("err: %s", err) - } - - // Change to the temporary directory - cwd, err := os.Getwd() - if err != nil { - t.Fatalf("err: %s", err) - } - if err := os.Chdir(dir); err != nil { - t.Fatalf("err: %s", err) - } - defer os.Chdir(cwd) - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - testFixturePath("init"), - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) - } - - if _, err := os.Stat("hello.tf"); err != nil { - t.Fatalf("err: %s", err) - } -} - func TestInit_empty(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) @@ -113,48 +53,6 @@ func TestInit_multipleArgs(t *testing.T) { } } -// https://github.com/hashicorp/terraform/issues/518 -func TestInit_dstInSrc(t *testing.T) { - dir := tempDir(t) - if err := os.MkdirAll(dir, 0755); err != nil { - t.Fatalf("err: %s", err) - } - - // Change to the temporary directory - cwd, err := os.Getwd() - if err != nil { - t.Fatalf("err: %s", err) - } - if err := os.Chdir(dir); err != nil { - t.Fatalf("err: %s", err) - } - defer os.Chdir(cwd) - - if _, err := os.Create("issue518.tf"); err != nil { - t.Fatalf("err: %s", err) - } - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - ".", - "foo", - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) - } - - if _, err := os.Stat(filepath.Join(dir, "foo", "issue518.tf")); err != nil { - t.Fatalf("err: %s", err) - } -} - func TestInit_get(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) @@ -182,39 +80,6 @@ func TestInit_get(t *testing.T) { } } -func TestInit_copyGet(t *testing.T) { - // Create a temporary working directory that is empty - td := tempDir(t) - os.MkdirAll(td, 0755) - defer os.RemoveAll(td) - defer testChdir(t, td)() - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - testFixturePath("init-get"), - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) - } - - // Check copy - if _, err := os.Stat("main.tf"); err != nil { - t.Fatalf("err: %s", err) - } - - output := ui.OutputWriter.String() - if !strings.Contains(output, "Get: file://") { - t.Fatalf("doesn't look like get: %s", output) - } -} - func TestInit_backend(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) @@ -380,13 +245,16 @@ func TestInit_backendConfigKV(t *testing.T) { } } -func TestInit_copyBackendDst(t *testing.T) { +func TestInit_targetSubdir(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) os.MkdirAll(td, 0755) defer os.RemoveAll(td) defer testChdir(t, td)() + // copy the source into a subdir + copy.CopyDir(testFixturePath("init-backend"), filepath.Join(td, "source")) + ui := new(cli.MockUi) c := &InitCommand{ Meta: Meta{ @@ -396,15 +264,18 @@ func TestInit_copyBackendDst(t *testing.T) { } args := []string{ - testFixturePath("init-backend"), - "dst", + "source", } if code := c.Run(args); code != 0 { t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) } - if _, err := os.Stat(filepath.Join( - "dst", DefaultDataDir, DefaultStateFilename)); err != nil { + if _, err := os.Stat(filepath.Join(td, "source", DefaultDataDir, DefaultStateFilename)); err != nil { + t.Fatalf("err: %s", err) + } + + // a data directory should not have been added to out working dir + if _, err := os.Stat(filepath.Join(td, DefaultDataDir)); !os.IsNotExist(err) { t.Fatalf("err: %s", err) } } @@ -700,149 +571,3 @@ func TestInit_providerLockFile(t *testing.T) { t.Errorf("wrong provider lock file contents\ngot: %s\nwant: %s", buf, wantLockFile) } } - -/* -func TestInit_remoteState(t *testing.T) { - tmp, cwd := testCwd(t) - defer testFixCwd(t, tmp, cwd) - - s := terraform.NewState() - conf, srv := testRemoteState(t, s, 200) - defer srv.Close() - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - "-backend", "HTTP", - "-backend-config", "address=" + conf.Config["address"], - testFixturePath("init"), - tmp, - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) - } - - if _, err := os.Stat(filepath.Join(tmp, "hello.tf")); err != nil { - t.Fatalf("err: %s", err) - } - - if _, err := os.Stat(filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)); err != nil { - t.Fatalf("missing state: %s", err) - } -} - -func TestInit_remoteStateSubdir(t *testing.T) { - tmp, cwd := testCwd(t) - defer testFixCwd(t, tmp, cwd) - subdir := filepath.Join(tmp, "subdir") - - s := terraform.NewState() - conf, srv := testRemoteState(t, s, 200) - defer srv.Close() - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - "-backend", "http", - "-backend-config", "address=" + conf.Config["address"], - testFixturePath("init"), - subdir, - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) - } - - if _, err := os.Stat(filepath.Join(subdir, "hello.tf")); err != nil { - t.Fatalf("err: %s", err) - } - - if _, err := os.Stat(filepath.Join(subdir, DefaultDataDir, DefaultStateFilename)); err != nil { - t.Fatalf("missing state: %s", err) - } -} - -func TestInit_remoteStateWithLocal(t *testing.T) { - tmp, cwd := testCwd(t) - defer testFixCwd(t, tmp, cwd) - - statePath := filepath.Join(tmp, DefaultStateFilename) - - // Write some state - f, err := os.Create(statePath) - if err != nil { - t.Fatalf("err: %s", err) - } - err = terraform.WriteState(testState(), f) - f.Close() - if err != nil { - t.Fatalf("err: %s", err) - } - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - "-backend", "http", - "-backend-config", "address=http://google.com", - testFixturePath("init"), - } - if code := c.Run(args); code == 0 { - t.Fatalf("should have failed: \n%s", ui.OutputWriter.String()) - } -} - -func TestInit_remoteStateWithRemote(t *testing.T) { - tmp, cwd := testCwd(t) - defer testFixCwd(t, tmp, cwd) - - statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename) - if err := os.MkdirAll(filepath.Dir(statePath), 0755); err != nil { - t.Fatalf("err: %s", err) - } - - // Write some state - f, err := os.Create(statePath) - if err != nil { - t.Fatalf("err: %s", err) - } - err = terraform.WriteState(testState(), f) - f.Close() - if err != nil { - t.Fatalf("err: %s", err) - } - - ui := new(cli.MockUi) - c := &InitCommand{ - Meta: Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - }, - } - - args := []string{ - "-backend", "http", - "-backend-config", "address=http://google.com", - testFixturePath("init"), - } - if code := c.Run(args); code == 0 { - t.Fatalf("should have failed: \n%s", ui.OutputWriter.String()) - } -} -*/