2017-07-08 03:49:41 +02:00
|
|
|
package e2etest
|
|
|
|
|
|
|
|
import (
|
2017-09-02 02:24:46 +02:00
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2017-08-16 15:48:51 +02:00
|
|
|
"path/filepath"
|
2017-09-02 02:24:46 +02:00
|
|
|
"runtime"
|
2017-07-08 03:49:41 +02:00
|
|
|
"strings"
|
|
|
|
"testing"
|
2017-08-16 15:48:51 +02:00
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/e2e"
|
2017-07-08 03:49:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestInitProviders(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// This test reaches out to releases.hashicorp.com to download the
|
|
|
|
// template provider, so it can only run if network access is allowed.
|
|
|
|
// We intentionally don't try to stub this here, because there's already
|
|
|
|
// a stubbed version of this in the "command" package and so the goal here
|
|
|
|
// is to test the interaction with the real repository.
|
|
|
|
skipIfCannotAccessNetwork(t)
|
|
|
|
|
2019-06-30 09:38:36 +02:00
|
|
|
fixturePath := filepath.Join("testdata", "template-provider")
|
2017-08-16 15:48:51 +02:00
|
|
|
tf := e2e.NewBinary(terraformBin, fixturePath)
|
2017-07-08 03:49:41 +02:00
|
|
|
defer tf.Close()
|
|
|
|
|
|
|
|
stdout, stderr, err := tf.Run("init")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if stderr != "" {
|
|
|
|
t.Errorf("unexpected stderr output:\n%s", stderr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
|
|
|
|
t.Errorf("success message is missing from output:\n%s", stdout)
|
|
|
|
}
|
|
|
|
|
2020-04-01 23:41:20 +02:00
|
|
|
if !strings.Contains(stdout, "- Installing registry.terraform.io/hashicorp/template v") {
|
2017-07-08 03:49:41 +02:00
|
|
|
t.Errorf("provider download message is missing from output:\n%s", stdout)
|
|
|
|
t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
|
|
|
|
}
|
|
|
|
|
2020-04-01 23:41:20 +02:00
|
|
|
if !strings.Contains(stdout, "* registry.terraform.io/hashicorp/template: version = ") {
|
2017-07-08 03:49:41 +02:00
|
|
|
t.Errorf("provider pinning recommendation is missing from output:\n%s", stdout)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2017-09-02 02:24:46 +02:00
|
|
|
|
2017-11-03 19:36:31 +01:00
|
|
|
func TestInitProvidersInternal(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// This test should _not_ reach out anywhere because the "terraform"
|
|
|
|
// provider is internal to the core terraform binary.
|
|
|
|
|
2019-06-30 09:38:36 +02:00
|
|
|
fixturePath := filepath.Join("testdata", "terraform-provider")
|
2017-11-03 19:36:31 +01:00
|
|
|
tf := e2e.NewBinary(terraformBin, fixturePath)
|
|
|
|
defer tf.Close()
|
|
|
|
|
|
|
|
stdout, stderr, err := tf.Run("init")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if stderr != "" {
|
|
|
|
t.Errorf("unexpected stderr output:\n%s", stderr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
|
|
|
|
t.Errorf("success message is missing from output:\n%s", stdout)
|
|
|
|
}
|
|
|
|
|
2020-04-02 00:32:07 +02:00
|
|
|
if strings.Contains(stdout, "Installing registry.terraform.io/hashicorp/terraform") {
|
2017-11-03 19:36:31 +01:00
|
|
|
// Shouldn't have downloaded anything with this config, because the
|
|
|
|
// provider is built in.
|
|
|
|
t.Errorf("provider download message appeared in output:\n%s", stdout)
|
|
|
|
}
|
|
|
|
|
2020-04-02 00:32:07 +02:00
|
|
|
if strings.Contains(stdout, "Installing terraform.io/builtin/terraform") {
|
|
|
|
// Shouldn't have downloaded anything with this config, because the
|
|
|
|
// provider is built in.
|
|
|
|
t.Errorf("provider download message appeared in output:\n%s", stdout)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInitProvidersVendored(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// This test will try to reach out to registry.terraform.io as one of the
|
|
|
|
// possible installation locations for
|
|
|
|
// registry.terraform.io/hashicorp/null, where it will find that
|
|
|
|
// versions do exist but will ultimately select the version that is
|
|
|
|
// vendored due to the version constraint.
|
|
|
|
skipIfCannotAccessNetwork(t)
|
|
|
|
|
|
|
|
fixturePath := filepath.Join("testdata", "vendored-provider")
|
|
|
|
tf := e2e.NewBinary(terraformBin, fixturePath)
|
|
|
|
defer tf.Close()
|
|
|
|
|
main: Consult local directories as potential mirrors of providers
This restores some of the local search directories we used to include when
searching for provider plugins in Terraform 0.12 and earlier. The
directory structures we are expecting in these are different than before,
so existing directory contents will not be compatible without
restructuring, but we need to retain support for these local directories
so that users can continue to sideload third-party provider plugins until
the explicit, first-class provider mirrors configuration (in CLI config)
is implemented, at which point users will be able to override these to
whatever directories they want.
This also includes some new search directories that are specific to the
operating system where Terraform is running, following the documented
layout conventions of that platform. In particular, this follows the
XDG Base Directory specification on Unix systems, which has been a
somewhat-common request to better support "sideloading" of packages via
standard Linux distribution package managers and other similar mechanisms.
While it isn't strictly necessary to add that now, it seems ideal to do
all of the changes to our search directory layout at once so that our
documentation about this can cleanly distinguish "0.12 and earlier" vs.
"0.13 and later", rather than having to document a complex sequence of
smaller changes.
Because this behavior is a result of the integration of package main with
package command, this behavior is verified using an e2etest rather than
a unit test. That test, TestInitProvidersVendored, is also fixed here to
create a suitable directory structure for the platform where the test is
being run. This fixes TestInitProvidersVendored.
2020-04-03 03:04:39 +02:00
|
|
|
// Our fixture dir has a generic os_arch dir, which we need to customize
|
|
|
|
// to the actual OS/arch where this test is running in order to get the
|
|
|
|
// desired result.
|
|
|
|
fixtMachineDir := tf.Path("terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch")
|
|
|
|
wantMachineDir := tf.Path("terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
|
|
|
|
err := os.Rename(fixtMachineDir, wantMachineDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
|
2020-04-02 00:32:07 +02:00
|
|
|
stdout, stderr, err := tf.Run("init")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if stderr != "" {
|
|
|
|
t.Errorf("unexpected stderr output:\n%s", stderr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
|
|
|
|
t.Errorf("success message is missing from output:\n%s", stdout)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.Contains(stdout, "- Installing registry.terraform.io/hashicorp/null v1.0.0+local") {
|
|
|
|
t.Errorf("provider download message is missing from output:\n%s", stdout)
|
|
|
|
t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
|
|
|
|
}
|
|
|
|
|
2017-11-03 19:36:31 +01:00
|
|
|
}
|
|
|
|
|
2017-09-02 02:24:46 +02:00
|
|
|
func TestInitProviders_pluginCache(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// This test reaches out to releases.hashicorp.com to access plugin
|
|
|
|
// metadata, and download the null plugin, though the template plugin
|
|
|
|
// should come from local cache.
|
|
|
|
skipIfCannotAccessNetwork(t)
|
|
|
|
|
2019-06-30 09:38:36 +02:00
|
|
|
fixturePath := filepath.Join("testdata", "plugin-cache")
|
2017-09-02 02:24:46 +02:00
|
|
|
tf := e2e.NewBinary(terraformBin, fixturePath)
|
|
|
|
defer tf.Close()
|
|
|
|
|
|
|
|
// Our fixture dir has a generic os_arch dir, which we need to customize
|
|
|
|
// to the actual OS/arch where this test is running in order to get the
|
|
|
|
// desired result.
|
2020-04-01 23:59:55 +02:00
|
|
|
fixtMachineDir := tf.Path("cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch")
|
|
|
|
wantMachineDir := tf.Path("cache/registry.terraform.io/hashicorp/template/2.1.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
|
|
|
|
err := os.Rename(fixtMachineDir, wantMachineDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %s", err)
|
|
|
|
}
|
2017-09-02 02:24:46 +02:00
|
|
|
|
|
|
|
cmd := tf.Cmd("init")
|
|
|
|
cmd.Env = append(cmd.Env, "TF_PLUGIN_CACHE_DIR=./cache")
|
|
|
|
cmd.Stdin = nil
|
|
|
|
cmd.Stderr = &bytes.Buffer{}
|
|
|
|
|
2020-04-01 23:59:55 +02:00
|
|
|
err = cmd.Run()
|
2017-09-02 02:24:46 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
stderr := cmd.Stderr.(*bytes.Buffer).String()
|
|
|
|
if stderr != "" {
|
2019-04-29 19:03:25 +02:00
|
|
|
t.Errorf("unexpected stderr output:\n%s\n", stderr)
|
2017-09-02 02:24:46 +02:00
|
|
|
}
|
|
|
|
|
2020-04-01 23:59:55 +02:00
|
|
|
path := fmt.Sprintf(".terraform/plugins/registry.terraform.io/hashicorp/template/2.1.0/%s_%s/terraform-provider-template_v2.1.0_x4", runtime.GOOS, runtime.GOARCH)
|
2017-09-02 02:24:46 +02:00
|
|
|
content, err := tf.ReadFile(path)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to read installed plugin from %s: %s", path, err)
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(string(content)) != "this is not a real plugin" {
|
|
|
|
t.Errorf("template plugin was not installed from local cache")
|
|
|
|
}
|
|
|
|
|
2020-04-01 23:59:55 +02:00
|
|
|
if !tf.FileExists(fmt.Sprintf(".terraform/plugins/registry.terraform.io/hashicorp/null/2.1.0/%s_%s/terraform-provider-null_v2.1.0_x4", runtime.GOOS, runtime.GOARCH)) {
|
2017-09-02 02:24:46 +02:00
|
|
|
t.Errorf("null plugin was not installed")
|
|
|
|
}
|
|
|
|
|
2020-04-01 23:59:55 +02:00
|
|
|
if !tf.FileExists(fmt.Sprintf("cache/registry.terraform.io/hashicorp/null/2.1.0/%s_%s/terraform-provider-null_v2.1.0_x4", runtime.GOOS, runtime.GOARCH)) {
|
2017-09-02 02:24:46 +02:00
|
|
|
t.Errorf("null plugin is not in cache after install")
|
|
|
|
}
|
|
|
|
}
|
2017-10-30 16:27:27 +01:00
|
|
|
|
|
|
|
func TestInit_fromModule(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// This test reaches out to registry.terraform.io and github.com to lookup
|
|
|
|
// and fetch a module.
|
|
|
|
skipIfCannotAccessNetwork(t)
|
|
|
|
|
2019-06-30 09:38:36 +02:00
|
|
|
fixturePath := filepath.Join("testdata", "empty")
|
2017-10-30 16:27:27 +01:00
|
|
|
tf := e2e.NewBinary(terraformBin, fixturePath)
|
|
|
|
defer tf.Close()
|
|
|
|
|
|
|
|
cmd := tf.Cmd("init", "-from-module=hashicorp/vault/aws")
|
|
|
|
cmd.Stdin = nil
|
|
|
|
cmd.Stderr = &bytes.Buffer{}
|
|
|
|
|
|
|
|
err := cmd.Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
stderr := cmd.Stderr.(*bytes.Buffer).String()
|
|
|
|
if stderr != "" {
|
|
|
|
t.Errorf("unexpected stderr output:\n%s", stderr)
|
|
|
|
}
|
|
|
|
|
|
|
|
content, err := tf.ReadFile("main.tf")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to read main.tf: %s", err)
|
|
|
|
}
|
|
|
|
if !bytes.Contains(content, []byte("vault")) {
|
|
|
|
t.Fatalf("main.tf doesn't appear to be a vault configuration: \n%s", content)
|
|
|
|
}
|
|
|
|
}
|