command: init to allow plugin init without backend init
Previously init would crash if given these options: -backend=false -get-plugins=true This is because the state is used as a source of provider dependency information, and we need to instantiate the backend to get the state. To avoid the crash, we now use the following adjusted behavior: - if -backend=true, we behave as before - if -backend=false, we instead try to instantiate the backend the same way any other command would, without modifying its configuration - if we're able to instantiate the backend, we use it to fetch state for dependency resolution purposes - if the backend is not instantiable then we assume it's not yet configured and proceed with a nil state, which may cause us to see an incomplete picture of the dependencies but still allows the install to succeed. Subsequently running "terraform plan" will not work until the backend is (re-)initialized, so the incomplete picture of required plugins is safe.
This commit is contained in:
parent
3dc7d618f7
commit
40e2fbb8e9
|
@ -172,21 +172,42 @@ func (c *InitCommand) Run(args []string) int {
|
|||
}
|
||||
}
|
||||
|
||||
if back == nil {
|
||||
// If we didn't initialize a backend then we'll try to at least
|
||||
// instantiate one. This might fail if it wasn't already initalized
|
||||
// by a previous run, so we must still expect that "back" may be nil
|
||||
// in code that follows.
|
||||
back, err = c.Backend(nil)
|
||||
if err != nil {
|
||||
// This is fine. We'll proceed with no backend, then.
|
||||
back = nil
|
||||
}
|
||||
}
|
||||
|
||||
var state *terraform.State
|
||||
|
||||
// If we have a functional backend (either just initialized or initialized
|
||||
// on a previous run) we'll use the current state as a potential source
|
||||
// of provider dependencies.
|
||||
if back != nil {
|
||||
sMgr, err := back.State(c.Workspace())
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Error loading state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := sMgr.RefreshState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Error refreshing state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
state = sMgr.State()
|
||||
}
|
||||
|
||||
// Now that we have loaded all modules, check the module tree for missing providers.
|
||||
sMgr, err := back.State(c.Workspace())
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Error loading state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := sMgr.RefreshState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Error refreshing state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
err = c.getProviders(path, sMgr.State(), flagUpgrade)
|
||||
err = c.getProviders(path, state, flagUpgrade)
|
||||
if err != nil {
|
||||
// this function provides its own output
|
||||
log.Printf("[ERROR] %s", err)
|
||||
|
|
|
@ -474,7 +474,9 @@ func TestInit_getProvider(t *testing.T) {
|
|||
providerInstaller: installer,
|
||||
}
|
||||
|
||||
args := []string{}
|
||||
args := []string{
|
||||
"-backend=false", // should be possible to install plugins without backend init
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue