github.com/pulumi/terraform@v1.4.0/pkg/command/taint_test.go (about)

     1  package command
     2  
     3  import (
     4  	"os"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/google/go-cmp/cmp"
     9  	"github.com/mitchellh/cli"
    10  
    11  	"github.com/pulumi/terraform/pkg/addrs"
    12  	"github.com/pulumi/terraform/pkg/states"
    13  )
    14  
    15  func TestTaint(t *testing.T) {
    16  	state := states.BuildState(func(s *states.SyncState) {
    17  		s.SetResourceInstanceCurrent(
    18  			addrs.Resource{
    19  				Mode: addrs.ManagedResourceMode,
    20  				Type: "test_instance",
    21  				Name: "foo",
    22  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    23  			&states.ResourceInstanceObjectSrc{
    24  				AttrsJSON: []byte(`{"id":"bar"}`),
    25  				Status:    states.ObjectReady,
    26  			},
    27  			addrs.AbsProviderConfig{
    28  				Provider: addrs.NewDefaultProvider("test"),
    29  				Module:   addrs.RootModule,
    30  			},
    31  		)
    32  	})
    33  	statePath := testStateFile(t, state)
    34  
    35  	ui := new(cli.MockUi)
    36  	view, _ := testView(t)
    37  	c := &TaintCommand{
    38  		Meta: Meta{
    39  			Ui:   ui,
    40  			View: view,
    41  		},
    42  	}
    43  
    44  	args := []string{
    45  		"-state", statePath,
    46  		"test_instance.foo",
    47  	}
    48  	if code := c.Run(args); code != 0 {
    49  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    50  	}
    51  
    52  	testStateOutput(t, statePath, testTaintStr)
    53  }
    54  
    55  func TestTaint_lockedState(t *testing.T) {
    56  	state := states.BuildState(func(s *states.SyncState) {
    57  		s.SetResourceInstanceCurrent(
    58  			addrs.Resource{
    59  				Mode: addrs.ManagedResourceMode,
    60  				Type: "test_instance",
    61  				Name: "foo",
    62  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    63  			&states.ResourceInstanceObjectSrc{
    64  				AttrsJSON: []byte(`{"id":"bar"}`),
    65  				Status:    states.ObjectReady,
    66  			},
    67  			addrs.AbsProviderConfig{
    68  				Provider: addrs.NewDefaultProvider("test"),
    69  				Module:   addrs.RootModule,
    70  			},
    71  		)
    72  	})
    73  	statePath := testStateFile(t, state)
    74  
    75  	unlock, err := testLockState(t, testDataDir, statePath)
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	defer unlock()
    80  	ui := new(cli.MockUi)
    81  	view, _ := testView(t)
    82  	c := &TaintCommand{
    83  		Meta: Meta{
    84  			Ui:   ui,
    85  			View: view,
    86  		},
    87  	}
    88  
    89  	args := []string{
    90  		"-state", statePath,
    91  		"test_instance.foo",
    92  	}
    93  	if code := c.Run(args); code == 0 {
    94  		t.Fatal("expected error")
    95  	}
    96  
    97  	output := ui.ErrorWriter.String()
    98  	if !strings.Contains(output, "lock") {
    99  		t.Fatal("command output does not look like a lock error:", output)
   100  	}
   101  }
   102  
   103  func TestTaint_backup(t *testing.T) {
   104  	// Get a temp cwd
   105  	testCwd(t)
   106  
   107  	// Write the temp state
   108  	state := states.BuildState(func(s *states.SyncState) {
   109  		s.SetResourceInstanceCurrent(
   110  			addrs.Resource{
   111  				Mode: addrs.ManagedResourceMode,
   112  				Type: "test_instance",
   113  				Name: "foo",
   114  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   115  			&states.ResourceInstanceObjectSrc{
   116  				AttrsJSON: []byte(`{"id":"bar"}`),
   117  				Status:    states.ObjectReady,
   118  			},
   119  			addrs.AbsProviderConfig{
   120  				Provider: addrs.NewDefaultProvider("test"),
   121  				Module:   addrs.RootModule,
   122  			},
   123  		)
   124  	})
   125  	testStateFileDefault(t, state)
   126  
   127  	ui := new(cli.MockUi)
   128  	view, _ := testView(t)
   129  	c := &TaintCommand{
   130  		Meta: Meta{
   131  			Ui:   ui,
   132  			View: view,
   133  		},
   134  	}
   135  
   136  	args := []string{
   137  		"test_instance.foo",
   138  	}
   139  	if code := c.Run(args); code != 0 {
   140  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   141  	}
   142  
   143  	testStateOutput(t, DefaultStateFilename+".backup", testTaintDefaultStr)
   144  	testStateOutput(t, DefaultStateFilename, testTaintStr)
   145  }
   146  
   147  func TestTaint_backupDisable(t *testing.T) {
   148  	// Get a temp cwd
   149  	testCwd(t)
   150  
   151  	// Write the temp state
   152  	state := states.BuildState(func(s *states.SyncState) {
   153  		s.SetResourceInstanceCurrent(
   154  			addrs.Resource{
   155  				Mode: addrs.ManagedResourceMode,
   156  				Type: "test_instance",
   157  				Name: "foo",
   158  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   159  			&states.ResourceInstanceObjectSrc{
   160  				AttrsJSON: []byte(`{"id":"bar"}`),
   161  				Status:    states.ObjectReady,
   162  			},
   163  			addrs.AbsProviderConfig{
   164  				Provider: addrs.NewDefaultProvider("test"),
   165  				Module:   addrs.RootModule,
   166  			},
   167  		)
   168  	})
   169  	testStateFileDefault(t, state)
   170  
   171  	ui := new(cli.MockUi)
   172  	view, _ := testView(t)
   173  	c := &TaintCommand{
   174  		Meta: Meta{
   175  			Ui:   ui,
   176  			View: view,
   177  		},
   178  	}
   179  
   180  	args := []string{
   181  		"-backup", "-",
   182  		"test_instance.foo",
   183  	}
   184  	if code := c.Run(args); code != 0 {
   185  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   186  	}
   187  
   188  	if _, err := os.Stat(DefaultStateFilename + ".backup"); err == nil {
   189  		t.Fatal("backup path should not exist")
   190  	}
   191  
   192  	testStateOutput(t, DefaultStateFilename, testTaintStr)
   193  }
   194  
   195  func TestTaint_badState(t *testing.T) {
   196  	ui := new(cli.MockUi)
   197  	view, _ := testView(t)
   198  	c := &TaintCommand{
   199  		Meta: Meta{
   200  			Ui:   ui,
   201  			View: view,
   202  		},
   203  	}
   204  
   205  	args := []string{
   206  		"-state", "i-should-not-exist-ever",
   207  		"foo",
   208  	}
   209  	if code := c.Run(args); code != 1 {
   210  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   211  	}
   212  }
   213  
   214  func TestTaint_defaultState(t *testing.T) {
   215  	// Get a temp cwd
   216  	testCwd(t)
   217  
   218  	// Write the temp state
   219  	state := states.BuildState(func(s *states.SyncState) {
   220  		s.SetResourceInstanceCurrent(
   221  			addrs.Resource{
   222  				Mode: addrs.ManagedResourceMode,
   223  				Type: "test_instance",
   224  				Name: "foo",
   225  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   226  			&states.ResourceInstanceObjectSrc{
   227  				AttrsJSON: []byte(`{"id":"bar"}`),
   228  				Status:    states.ObjectReady,
   229  			},
   230  			addrs.AbsProviderConfig{
   231  				Provider: addrs.NewDefaultProvider("test"),
   232  				Module:   addrs.RootModule,
   233  			},
   234  		)
   235  	})
   236  	testStateFileDefault(t, state)
   237  
   238  	ui := new(cli.MockUi)
   239  	view, _ := testView(t)
   240  	c := &TaintCommand{
   241  		Meta: Meta{
   242  			Ui:   ui,
   243  			View: view,
   244  		},
   245  	}
   246  
   247  	args := []string{
   248  		"test_instance.foo",
   249  	}
   250  	if code := c.Run(args); code != 0 {
   251  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   252  	}
   253  
   254  	testStateOutput(t, DefaultStateFilename, testTaintStr)
   255  }
   256  
   257  func TestTaint_defaultWorkspaceState(t *testing.T) {
   258  	// Get a temp cwd
   259  	testCwd(t)
   260  
   261  	state := states.BuildState(func(s *states.SyncState) {
   262  		s.SetResourceInstanceCurrent(
   263  			addrs.Resource{
   264  				Mode: addrs.ManagedResourceMode,
   265  				Type: "test_instance",
   266  				Name: "foo",
   267  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   268  			&states.ResourceInstanceObjectSrc{
   269  				AttrsJSON: []byte(`{"id":"bar"}`),
   270  				Status:    states.ObjectReady,
   271  			},
   272  			addrs.AbsProviderConfig{
   273  				Provider: addrs.NewDefaultProvider("test"),
   274  				Module:   addrs.RootModule,
   275  			},
   276  		)
   277  	})
   278  	testWorkspace := "development"
   279  	path := testStateFileWorkspaceDefault(t, testWorkspace, state)
   280  
   281  	ui := new(cli.MockUi)
   282  	view, _ := testView(t)
   283  	meta := Meta{Ui: ui, View: view}
   284  	meta.SetWorkspace(testWorkspace)
   285  	c := &TaintCommand{
   286  		Meta: meta,
   287  	}
   288  
   289  	args := []string{
   290  		"test_instance.foo",
   291  	}
   292  	if code := c.Run(args); code != 0 {
   293  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   294  	}
   295  
   296  	testStateOutput(t, path, testTaintStr)
   297  }
   298  
   299  func TestTaint_missing(t *testing.T) {
   300  	state := states.BuildState(func(s *states.SyncState) {
   301  		s.SetResourceInstanceCurrent(
   302  			addrs.Resource{
   303  				Mode: addrs.ManagedResourceMode,
   304  				Type: "test_instance",
   305  				Name: "foo",
   306  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   307  			&states.ResourceInstanceObjectSrc{
   308  				AttrsJSON: []byte(`{"id":"bar"}`),
   309  				Status:    states.ObjectReady,
   310  			},
   311  			addrs.AbsProviderConfig{
   312  				Provider: addrs.NewDefaultProvider("test"),
   313  				Module:   addrs.RootModule,
   314  			},
   315  		)
   316  	})
   317  	statePath := testStateFile(t, state)
   318  
   319  	ui := new(cli.MockUi)
   320  	view, _ := testView(t)
   321  	c := &TaintCommand{
   322  		Meta: Meta{
   323  			Ui:   ui,
   324  			View: view,
   325  		},
   326  	}
   327  
   328  	args := []string{
   329  		"-state", statePath,
   330  		"test_instance.bar",
   331  	}
   332  	if code := c.Run(args); code == 0 {
   333  		t.Fatalf("bad: %d\n\n%s", code, ui.OutputWriter.String())
   334  	}
   335  }
   336  
   337  func TestTaint_missingAllow(t *testing.T) {
   338  	state := states.BuildState(func(s *states.SyncState) {
   339  		s.SetResourceInstanceCurrent(
   340  			addrs.Resource{
   341  				Mode: addrs.ManagedResourceMode,
   342  				Type: "test_instance",
   343  				Name: "foo",
   344  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   345  			&states.ResourceInstanceObjectSrc{
   346  				AttrsJSON: []byte(`{"id":"bar"}`),
   347  				Status:    states.ObjectReady,
   348  			},
   349  			addrs.AbsProviderConfig{
   350  				Provider: addrs.NewDefaultProvider("test"),
   351  				Module:   addrs.RootModule,
   352  			},
   353  		)
   354  	})
   355  	statePath := testStateFile(t, state)
   356  
   357  	ui := new(cli.MockUi)
   358  	view, _ := testView(t)
   359  	c := &TaintCommand{
   360  		Meta: Meta{
   361  			Ui:   ui,
   362  			View: view,
   363  		},
   364  	}
   365  
   366  	args := []string{
   367  		"-allow-missing",
   368  		"-state", statePath,
   369  		"test_instance.bar",
   370  	}
   371  	if code := c.Run(args); code != 0 {
   372  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   373  	}
   374  
   375  	// Check for the warning
   376  	actual := strings.TrimSpace(ui.ErrorWriter.String())
   377  	expected := strings.TrimSpace(`
   378  Warning: No such resource instance
   379  
   380  Resource instance test_instance.bar was not found, but this is not an error
   381  because -allow-missing was set.
   382  
   383  `)
   384  	if diff := cmp.Diff(expected, actual); diff != "" {
   385  		t.Fatalf("wrong output\n%s", diff)
   386  	}
   387  }
   388  
   389  func TestTaint_stateOut(t *testing.T) {
   390  	// Get a temp cwd
   391  	testCwd(t)
   392  
   393  	// Write the temp state
   394  	state := states.BuildState(func(s *states.SyncState) {
   395  		s.SetResourceInstanceCurrent(
   396  			addrs.Resource{
   397  				Mode: addrs.ManagedResourceMode,
   398  				Type: "test_instance",
   399  				Name: "foo",
   400  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   401  			&states.ResourceInstanceObjectSrc{
   402  				AttrsJSON: []byte(`{"id":"bar"}`),
   403  				Status:    states.ObjectReady,
   404  			},
   405  			addrs.AbsProviderConfig{
   406  				Provider: addrs.NewDefaultProvider("test"),
   407  				Module:   addrs.RootModule,
   408  			},
   409  		)
   410  	})
   411  	testStateFileDefault(t, state)
   412  
   413  	ui := new(cli.MockUi)
   414  	view, _ := testView(t)
   415  	c := &TaintCommand{
   416  		Meta: Meta{
   417  			Ui:   ui,
   418  			View: view,
   419  		},
   420  	}
   421  
   422  	args := []string{
   423  		"-state-out", "foo",
   424  		"test_instance.foo",
   425  	}
   426  	if code := c.Run(args); code != 0 {
   427  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   428  	}
   429  
   430  	testStateOutput(t, DefaultStateFilename, testTaintDefaultStr)
   431  	testStateOutput(t, "foo", testTaintStr)
   432  }
   433  
   434  func TestTaint_module(t *testing.T) {
   435  	state := states.BuildState(func(s *states.SyncState) {
   436  		s.SetResourceInstanceCurrent(
   437  			addrs.Resource{
   438  				Mode: addrs.ManagedResourceMode,
   439  				Type: "test_instance",
   440  				Name: "foo",
   441  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   442  			&states.ResourceInstanceObjectSrc{
   443  				AttrsJSON: []byte(`{"id":"bar"}`),
   444  				Status:    states.ObjectReady,
   445  			},
   446  			addrs.AbsProviderConfig{
   447  				Provider: addrs.NewDefaultProvider("test"),
   448  				Module:   addrs.RootModule,
   449  			},
   450  		)
   451  		s.SetResourceInstanceCurrent(
   452  			addrs.Resource{
   453  				Mode: addrs.ManagedResourceMode,
   454  				Type: "test_instance",
   455  				Name: "blah",
   456  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
   457  			&states.ResourceInstanceObjectSrc{
   458  				AttrsJSON: []byte(`{"id":"blah"}`),
   459  				Status:    states.ObjectReady,
   460  			},
   461  			addrs.AbsProviderConfig{
   462  				Provider: addrs.NewDefaultProvider("test"),
   463  				Module:   addrs.RootModule,
   464  			},
   465  		)
   466  	})
   467  	statePath := testStateFile(t, state)
   468  
   469  	ui := new(cli.MockUi)
   470  	view, _ := testView(t)
   471  	c := &TaintCommand{
   472  		Meta: Meta{
   473  			Ui:   ui,
   474  			View: view,
   475  		},
   476  	}
   477  
   478  	args := []string{
   479  		"-state", statePath,
   480  		"module.child.test_instance.blah",
   481  	}
   482  	if code := c.Run(args); code != 0 {
   483  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   484  	}
   485  
   486  	testStateOutput(t, statePath, testTaintModuleStr)
   487  }
   488  
   489  func TestTaint_checkRequiredVersion(t *testing.T) {
   490  	// Create a temporary working directory that is empty
   491  	td := t.TempDir()
   492  	testCopyDir(t, testFixturePath("command-check-required-version"), td)
   493  	defer testChdir(t, td)()
   494  
   495  	// Write the temp state
   496  	state := states.BuildState(func(s *states.SyncState) {
   497  		s.SetResourceInstanceCurrent(
   498  			addrs.Resource{
   499  				Mode: addrs.ManagedResourceMode,
   500  				Type: "test_instance",
   501  				Name: "foo",
   502  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   503  			&states.ResourceInstanceObjectSrc{
   504  				AttrsJSON: []byte(`{"id":"bar"}`),
   505  				Status:    states.ObjectReady,
   506  			},
   507  			addrs.AbsProviderConfig{
   508  				Provider: addrs.NewDefaultProvider("test"),
   509  				Module:   addrs.RootModule,
   510  			},
   511  		)
   512  	})
   513  	path := testStateFile(t, state)
   514  
   515  	ui := cli.NewMockUi()
   516  	view, _ := testView(t)
   517  	c := &TaintCommand{
   518  		Meta: Meta{
   519  			testingOverrides: metaOverridesForProvider(testProvider()),
   520  			Ui:               ui,
   521  			View:             view,
   522  		},
   523  	}
   524  
   525  	args := []string{"test_instance.foo"}
   526  	if code := c.Run(args); code != 1 {
   527  		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
   528  	}
   529  
   530  	// State is unchanged
   531  	testStateOutput(t, path, testTaintDefaultStr)
   532  
   533  	// Required version diags are correct
   534  	errStr := ui.ErrorWriter.String()
   535  	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
   536  		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
   537  	}
   538  	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
   539  		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
   540  	}
   541  }
   542  
   543  const testTaintStr = `
   544  test_instance.foo: (tainted)
   545    ID = bar
   546    provider = provider["registry.terraform.io/hashicorp/test"]
   547  `
   548  
   549  const testTaintDefaultStr = `
   550  test_instance.foo:
   551    ID = bar
   552    provider = provider["registry.terraform.io/hashicorp/test"]
   553  `
   554  
   555  const testTaintModuleStr = `
   556  test_instance.foo:
   557    ID = bar
   558    provider = provider["registry.terraform.io/hashicorp/test"]
   559  
   560  module.child:
   561    test_instance.blah: (tainted)
   562      ID = blah
   563      provider = provider["registry.terraform.io/hashicorp/test"]
   564  `