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