Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

helper/resource: Ensure Terraform CLI logs are written to TF_LOG_PATH_MASK environment variable value when both TF_ACC_LOG_PATH and TF_LOG_PATH_MASK are set #938

Merged
merged 3 commits into from Apr 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/938.txt
@@ -0,0 +1,3 @@
```release-note:bug
helper/resource: Ensured Terraform CLI logs are written to `TF_LOG_PATH_MASK` environment variable value when both `TF_ACC_LOG_PATH` and `TF_LOG_PATH_MASK` are set
```
6 changes: 6 additions & 0 deletions internal/logging/keys.go
Expand Up @@ -31,6 +31,12 @@ const (
// The TestStep number of the test being executed. Starts at 1.
KeyTestStepNumber = "test_step_number"

// The path to the Terraform CLI logging file used for an acceptance test.
//
// This should match where the rest of the acceptance test logs are going
// already, but is provided for troubleshooting in case it does not.
KeyTestTerraformLogPath = "test_terraform_log_path"

// The path to the Terraform CLI used for an acceptance test.
KeyTestTerraformPath = "test_terraform_path"

Expand Down
11 changes: 11 additions & 0 deletions internal/plugintest/environment_variables.go
Expand Up @@ -14,8 +14,19 @@ const (
// testing. This value sets TF_LOG_PATH in a safe manner when executing
// Terraform CLI commands, which would otherwise be ignored since it could
// interfere with how the underlying execution is performed.
//
// If TF_LOG_PATH_MASK is set, it takes precedence over this value.
EnvTfAccLogPath = "TF_ACC_LOG_PATH"

// Environment variable with path containing the string %s, which is
// replaced with the test name, to save separate Terraform logs during
// acceptance testing. This value sets TF_LOG_PATH in a safe manner when
// executing Terraform CLI commands, which would otherwise be ignored since
// it could interfere with how the underlying execution is performed.
//
// Takes precedence over TF_ACC_LOG_PATH.
EnvTfLogPathMask = "TF_LOG_PATH_MASK"

// Environment variable with acceptance testing Terraform CLI version to
// download from releases.hashicorp.com, checksum verify, and install. The
// value can be any valid Terraform CLI version, such as 1.1.6, with or
Expand Down
1 change: 1 addition & 0 deletions internal/plugintest/guard.go
Expand Up @@ -19,6 +19,7 @@ type TestControl interface {
Log(args ...interface{})
FailNow()
SkipNow()
Name() string
}

// testingT wraps a TestControl to recover some of the convenience behaviors
Expand Down
48 changes: 46 additions & 2 deletions internal/plugintest/helper.go
Expand Up @@ -2,9 +2,11 @@ package plugintest

import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/hashicorp/terraform-exec/tfexec"
"github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging"
Expand Down Expand Up @@ -102,7 +104,7 @@ func (h *Helper) Close() error {
// If the working directory object is not itself closed by the time the test
// program exits, the Close method on the helper itself will attempt to
// delete it.
func (h *Helper) NewWorkingDir(ctx context.Context) (*WorkingDir, error) {
func (h *Helper) NewWorkingDir(ctx context.Context, t TestControl) (*WorkingDir, error) {
dir, err := ioutil.TempDir(h.baseDir, "work")
if err != nil {
return nil, err
Expand All @@ -124,6 +126,48 @@ func (h *Helper) NewWorkingDir(ctx context.Context) (*WorkingDir, error) {
return nil, fmt.Errorf("unable to create terraform-exec instance: %w", err)
}

err = tf.SetDisablePluginTLS(true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at https://pkg.go.dev/github.com/hashicorp/terraform-exec@v0.16.1/tfexec but I can't find exactly what setting that TF_DISABLE_PLUGIN_TLS means.

Does it mean that we want TF to not fetch providers using https?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


if err != nil {
return nil, fmt.Errorf("unable to disable terraform-exec plugin TLS: %w", err)
}

err = tf.SetSkipProviderVerify(true) // Only required for Terraform CLI 0.12.x

var mismatch *tfexec.ErrVersionMismatch
if err != nil && !errors.As(err, &mismatch) {
return nil, fmt.Errorf("unable to disable terraform-exec provider verification: %w", err)
}

var logPath, logPathEnvVar string

if tfAccLogPath := os.Getenv(EnvTfAccLogPath); tfAccLogPath != "" {
logPath = tfAccLogPath
logPathEnvVar = EnvTfAccLogPath
}

// Similar to helper/logging.LogOutput() and
// terraform-plugin-log/tfsdklog.RegisterTestSink(), the TF_LOG_PATH_MASK
// environment variable should take precedence over TF_ACC_LOG_PATH.
if tfLogPathMask := os.Getenv(EnvTfLogPathMask); tfLogPathMask != "" {
// Escape special characters which may appear if we have subtests
testName := strings.Replace(t.Name(), "/", "__", -1)
logPath = fmt.Sprintf(tfLogPathMask, testName)
logPathEnvVar = EnvTfLogPathMask
}

if logPath != "" {
logging.HelperResourceTrace(
ctx,
fmt.Sprintf("Setting terraform-exec log path via %s environment variable", logPathEnvVar),
map[string]interface{}{logging.KeyTestTerraformLogPath: logPath},
)

if err := tf.SetLogPath(logPath); err != nil {
return nil, fmt.Errorf("unable to set terraform-exec log path (%s): %w", logPath, err)
}
}

return &WorkingDir{
h: h,
tf: tf,
Expand All @@ -138,7 +182,7 @@ func (h *Helper) NewWorkingDir(ctx context.Context) (*WorkingDir, error) {
func (h *Helper) RequireNewWorkingDir(ctx context.Context, t TestControl) *WorkingDir {
t.Helper()

wd, err := h.NewWorkingDir(ctx)
wd, err := h.NewWorkingDir(ctx, t)
if err != nil {
t := testingT{t}
t.Fatalf("failed to create new working directory: %s", err)
Expand Down
17 changes: 0 additions & 17 deletions internal/plugintest/working_dir.go
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -91,22 +90,6 @@ func (wd *WorkingDir) SetConfig(ctx context.Context, cfg string) error {
}
wd.configFilename = outFilename

var mismatch *tfexec.ErrVersionMismatch
err = wd.tf.SetDisablePluginTLS(true)
if err != nil && !errors.As(err, &mismatch) {
return err
}
err = wd.tf.SetSkipProviderVerify(true)
if err != nil && !errors.As(err, &mismatch) {
return err
}

if p := os.Getenv(EnvTfAccLogPath); p != "" {
if err := wd.tf.SetLogPath(p); err != nil {
return fmt.Errorf("unable to set log path: %w", err)
}
}

// Changing configuration invalidates any saved plan.
err = wd.ClearPlan(ctx)
if err != nil {
Expand Down