mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-03-12 07:01:03 -04:00
Once we've installed the necessary plugins, we'll do one more walk of the available plugins and record the SHA256 hashes of all of the plugins we select in the provider lock file. The file we write here gets read when we're building ContextOpts to initialize the main terraform context, so any command that works with the context will then fail if any of the provider binaries change.
874 lines
20 KiB
Go
874 lines
20 KiB
Go
package command
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
atlas "github.com/hashicorp/atlas-go/v1"
|
|
"github.com/hashicorp/terraform/helper/copy"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
"github.com/mitchellh/cli"
|
|
)
|
|
|
|
func TestPush_good(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
testFixturePath("push"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
variables := make(map[string]interface{})
|
|
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
}
|
|
|
|
func TestPush_goodBackendInit(t *testing.T) {
|
|
// Create a temporary working directory that is empty
|
|
td := tempDir(t)
|
|
copy.CopyDir(testFixturePath("push-backend-new"), td)
|
|
defer os.RemoveAll(td)
|
|
defer testChdir(t, td)()
|
|
|
|
// init backend
|
|
ui := new(cli.MockUi)
|
|
ci := &InitCommand{
|
|
Meta: Meta{
|
|
Ui: ui,
|
|
},
|
|
}
|
|
if code := ci.Run(nil); code != 0 {
|
|
t.Fatalf("bad: %d\n%s", code, ui.ErrorWriter)
|
|
}
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui = new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
td,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
// Expected weird behavior, doesn't affect unpackaging
|
|
".terraform/",
|
|
".terraform/",
|
|
".terraform/plugins/",
|
|
fmt.Sprintf(".terraform/plugins/%s_%s/", runtime.GOOS, runtime.GOARCH),
|
|
fmt.Sprintf(".terraform/plugins/%s_%s/providers.json", runtime.GOOS, runtime.GOARCH),
|
|
".terraform/terraform.tfstate",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
variables := make(map[string]interface{})
|
|
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "hello" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
}
|
|
|
|
func TestPush_noUploadModules(t *testing.T) {
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
// Path of the test. We have to do some renaming to avoid our own
|
|
// VCS getting in the way.
|
|
path := testFixturePath("push-no-upload")
|
|
defer os.RemoveAll(filepath.Join(path, ".terraform"))
|
|
|
|
// Move into that directory
|
|
defer testChdir(t, path)()
|
|
|
|
// Do a "terraform get"
|
|
{
|
|
ui := new(cli.MockUi)
|
|
c := &GetCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
}
|
|
|
|
if code := c.Run([]string{}); code != 0 {
|
|
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
|
}
|
|
}
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
defer os.Remove(testStateFileRemote(t, s))
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
"-name=mitchellh/tf-test",
|
|
"-upload-modules=false",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
// NOTE: The duplicates below are not ideal but are how things work
|
|
// currently due to how we manually add the files to the archive. This
|
|
// is definitely a "bug" we can fix in the future.
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
".terraform/terraform.tfstate",
|
|
"child/",
|
|
"child/main.tf",
|
|
"main.tf",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestPush_input(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("foo\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
testFixturePath("push-input"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
variables := map[string]interface{}{
|
|
"foo": "foo",
|
|
}
|
|
|
|
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions.Variables)
|
|
}
|
|
}
|
|
|
|
// We want a variable from atlas to fill a missing variable locally
|
|
func TestPush_inputPartial(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{
|
|
File: archivePath,
|
|
GetResult: map[string]atlas.TFVar{
|
|
"foo": atlas.TFVar{Key: "foo", Value: "bar"},
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("foo\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
testFixturePath("push-input-partial"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
expectedTFVars := []atlas.TFVar{
|
|
{Key: "bar", Value: "foo"},
|
|
{Key: "foo", Value: "bar"},
|
|
}
|
|
if !reflect.DeepEqual(client.UpsertOptions.TFVars, expectedTFVars) {
|
|
t.Logf("expected: %#v", expectedTFVars)
|
|
t.Fatalf("got: %#v", client.UpsertOptions.TFVars)
|
|
}
|
|
}
|
|
|
|
// This tests that the push command will override Atlas variables
|
|
// if requested.
|
|
func TestPush_localOverride(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
// Provided vars should override existing ones
|
|
client.GetResult = map[string]atlas.TFVar{
|
|
"foo": atlas.TFVar{
|
|
Key: "foo",
|
|
Value: "old",
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
"-overwrite=foo",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
expectedTFVars := pushTFVars()
|
|
|
|
if !reflect.DeepEqual(client.UpsertOptions.TFVars, expectedTFVars) {
|
|
t.Logf("expected: %#v", expectedTFVars)
|
|
t.Fatalf("got: %#v", client.UpsertOptions.TFVars)
|
|
}
|
|
}
|
|
|
|
// This tests that the push command will override Atlas variables
|
|
// even if we don't have it defined locally
|
|
func TestPush_remoteOverride(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
// Provided vars should override existing ones
|
|
client.GetResult = map[string]atlas.TFVar{
|
|
"remote": atlas.TFVar{
|
|
Key: "remote",
|
|
Value: "old",
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
"-overwrite=remote",
|
|
"-var",
|
|
"remote=new",
|
|
path,
|
|
}
|
|
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
found := false
|
|
// find the "remote" var and make sure we're going to set it
|
|
for _, tfVar := range client.UpsertOptions.TFVars {
|
|
if tfVar.Key == "remote" {
|
|
found = true
|
|
if tfVar.Value != "new" {
|
|
t.Log("'remote' variable should be set to 'new'")
|
|
t.Fatalf("sending instead: %#v", tfVar)
|
|
}
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Fatal("'remote' variable not being sent to atlas")
|
|
}
|
|
}
|
|
|
|
// This tests that the push command prefers Atlas variables over
|
|
// local ones.
|
|
func TestPush_preferAtlas(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
// Provided vars should override existing ones
|
|
client.GetResult = map[string]atlas.TFVar{
|
|
"foo": atlas.TFVar{
|
|
Key: "foo",
|
|
Value: "old",
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
// change the expected response to match our change
|
|
expectedTFVars := pushTFVars()
|
|
for i, v := range expectedTFVars {
|
|
if v.Key == "foo" {
|
|
expectedTFVars[i] = atlas.TFVar{Key: "foo", Value: "old"}
|
|
}
|
|
}
|
|
|
|
if !reflect.DeepEqual(expectedTFVars, client.UpsertOptions.TFVars) {
|
|
t.Logf("expected: %#v", expectedTFVars)
|
|
t.Fatalf("got: %#v", client.UpsertOptions.TFVars)
|
|
}
|
|
}
|
|
|
|
// This tests that the push command will send the variables in tfvars
|
|
func TestPush_tfvars(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
"-var",
|
|
"bar=[1,2]",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
//now check TFVars
|
|
tfvars := pushTFVars()
|
|
// update bar to match cli value
|
|
for i, v := range tfvars {
|
|
if v.Key == "bar" {
|
|
tfvars[i].Value = "[1, 2]"
|
|
tfvars[i].IsHCL = true
|
|
}
|
|
}
|
|
|
|
for i, expected := range tfvars {
|
|
got := client.UpsertOptions.TFVars[i]
|
|
if got != expected {
|
|
t.Logf("%2d expected: %#v", i, expected)
|
|
t.Fatalf(" got: %#v", got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPush_name(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-name", "bar",
|
|
"-vcs=false",
|
|
testFixturePath("push"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "bar" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
}
|
|
|
|
func TestPush_noState(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
if code := c.Run(args); code != 1 {
|
|
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
|
}
|
|
}
|
|
|
|
func TestPush_noRemoteState(t *testing.T) {
|
|
// Create a temporary working directory that is empty
|
|
td := tempDir(t)
|
|
copy.CopyDir(testFixturePath("push-no-remote"), td)
|
|
defer os.RemoveAll(td)
|
|
defer testChdir(t, td)()
|
|
|
|
state := &terraform.State{
|
|
Modules: []*terraform.ModuleState{
|
|
&terraform.ModuleState{
|
|
Path: []string{"root"},
|
|
Resources: map[string]*terraform.ResourceState{
|
|
"test_instance.foo": &terraform.ResourceState{
|
|
Type: "test_instance",
|
|
Primary: &terraform.InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
statePath := testStateFile(t, state)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
Ui: ui,
|
|
},
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
"-state", statePath,
|
|
td,
|
|
}
|
|
if code := c.Run(args); code != 1 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
errStr := ui.ErrorWriter.String()
|
|
if !strings.Contains(errStr, "remote backend") {
|
|
t.Fatalf("bad: %s", errStr)
|
|
}
|
|
}
|
|
|
|
func TestPush_plan(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Create a plan
|
|
planPath := testPlanFile(t, &terraform.Plan{
|
|
Module: testModule(t, "apply"),
|
|
})
|
|
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
}
|
|
|
|
args := []string{planPath}
|
|
if code := c.Run(args); code != 1 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
}
|
|
|
|
func testArchiveStr(t *testing.T, path string) []string {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
// Ungzip
|
|
gzipR, err := gzip.NewReader(f)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Accumulator
|
|
result := make([]string, 0, 10)
|
|
|
|
// Untar
|
|
tarR := tar.NewReader(gzipR)
|
|
for {
|
|
header, err := tarR.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
result = append(result, header.Name)
|
|
}
|
|
|
|
sort.Strings(result)
|
|
return result
|
|
}
|
|
|
|
// we always quote map keys to be safe
|
|
func pushTFVars() []atlas.TFVar {
|
|
return []atlas.TFVar{
|
|
{Key: "bar", Value: "foo", IsHCL: false},
|
|
{Key: "baz", Value: `{
|
|
"A" = "a"
|
|
}`, IsHCL: true},
|
|
{Key: "fob", Value: `["a", "quotes \"in\" quotes"]`, IsHCL: true},
|
|
{Key: "foo", Value: "bar", IsHCL: false},
|
|
}
|
|
}
|
|
|
|
// the structure returned from the push-tfvars test fixture
|
|
func pushTFVarsMap() map[string]atlas.TFVar {
|
|
vars := make(map[string]atlas.TFVar)
|
|
for _, v := range pushTFVars() {
|
|
vars[v.Key] = v
|
|
}
|
|
return vars
|
|
}
|