command: init -upgrade for provider plugins
Now when -upgrade is provided to "terraform init" (and plugin installation isn't disabled) it will: - ignore the contents of the auto-install plugin directory when deciding what is "available", thus causing anything there to be reinstalled, possibly at a newer version. - if installation completes successfully, purge from the auto-install plugin directory any plugin-looking files that aren't in the set of chosen plugins. As before, plugins outside of the auto-install directory are able to take precedence over the auto-install ones, and these will never be upgraded nor purged. The thinking here is that the auto-install directory is an implementation detail directly managed by Terraform, and so it's Terraform's responsibility to automatically keep it clean as plugins are upgraded. We don't yet have the -plugin-dir option implemented, but once it is it should circumvent all of this behavior and just expect providers to be already available in the given directory, meaning that nothing will be auto-installed, -upgraded or -purged.
This commit is contained in:
parent
af4c82d151
commit
6979a07754
|
@ -213,7 +213,14 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
available := c.providerPluginSet()
|
var available discovery.PluginMetaSet
|
||||||
|
if upgrade {
|
||||||
|
// If we're in upgrade mode, we ignore any auto-installed plugins
|
||||||
|
// in "available", causing us to reinstall and possibly upgrade them.
|
||||||
|
available = c.providerPluginManuallyInstalledSet()
|
||||||
|
} else {
|
||||||
|
available = c.providerPluginSet()
|
||||||
|
}
|
||||||
requirements := terraform.ModuleTreeDependencies(mod, state).AllPluginRequirements()
|
requirements := terraform.ModuleTreeDependencies(mod, state).AllPluginRequirements()
|
||||||
missing := c.missingPlugins(available, requirements)
|
missing := c.missingPlugins(available, requirements)
|
||||||
|
|
||||||
|
@ -253,6 +260,20 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if upgrade {
|
||||||
|
// Purge any auto-installed plugins that aren't being used.
|
||||||
|
purged, err := c.providerInstaller.PurgeUnused(chosen)
|
||||||
|
if err != nil {
|
||||||
|
// Failure to purge old plugins is not a fatal error
|
||||||
|
c.Ui.Warn(fmt.Sprintf("failed to purge unused plugins: %s", err))
|
||||||
|
}
|
||||||
|
if purged != nil {
|
||||||
|
for meta := range purged {
|
||||||
|
log.Printf("[DEBUG] Purged unused %s plugin %s", meta.Name, meta.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If any providers have "floating" versions (completely unconstrained)
|
// If any providers have "floating" versions (completely unconstrained)
|
||||||
// we'll suggest the user constrain with a pessimistic constraint to
|
// we'll suggest the user constrain with a pessimistic constraint to
|
||||||
// avoid implicitly adopting a later major release.
|
// avoid implicitly adopting a later major release.
|
||||||
|
|
|
@ -5,7 +5,9 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -492,6 +494,98 @@ func TestInit_getProvider(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInit_getUpgradePlugins(t *testing.T) {
|
||||||
|
// Create a temporary working directory that is empty
|
||||||
|
td := tempDir(t)
|
||||||
|
copy.CopyDir(testFixturePath("init-get-providers"), td)
|
||||||
|
defer os.RemoveAll(td)
|
||||||
|
defer testChdir(t, td)()
|
||||||
|
|
||||||
|
ui := new(cli.MockUi)
|
||||||
|
m := Meta{
|
||||||
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||||
|
Ui: ui,
|
||||||
|
}
|
||||||
|
|
||||||
|
installer := &mockProviderInstaller{
|
||||||
|
Providers: map[string][]string{
|
||||||
|
// looking for an exact version
|
||||||
|
"exact": []string{"1.2.3"},
|
||||||
|
// config requires >= 2.3.3
|
||||||
|
"greater_than": []string{"2.3.4", "2.3.3", "2.3.0"},
|
||||||
|
// config specifies
|
||||||
|
"between": []string{"3.4.5", "2.3.4", "1.2.3"},
|
||||||
|
},
|
||||||
|
|
||||||
|
Dir: m.pluginDir(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := os.MkdirAll(m.pluginDir(), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
exactUnwanted := filepath.Join(m.pluginDir(), installer.FileName("exact", "0.0.1"))
|
||||||
|
err = ioutil.WriteFile(exactUnwanted, []byte{}, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
greaterThanUnwanted := filepath.Join(m.pluginDir(), installer.FileName("greater_than", "2.3.3"))
|
||||||
|
err = ioutil.WriteFile(greaterThanUnwanted, []byte{}, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
betweenOverride := installer.FileName("between", "2.3.4") // intentionally directly in cwd, and should override auto-install
|
||||||
|
err = ioutil.WriteFile(betweenOverride, []byte{}, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &InitCommand{
|
||||||
|
Meta: m,
|
||||||
|
providerInstaller: installer,
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"-upgrade=true",
|
||||||
|
}
|
||||||
|
if code := c.Run(args); code != 0 {
|
||||||
|
t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(m.pluginDir())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !installer.PurgeUnusedCalled {
|
||||||
|
t.Errorf("init -upgrade didn't purge providers, but should have")
|
||||||
|
}
|
||||||
|
|
||||||
|
gotFilenames := make([]string, len(files))
|
||||||
|
for i, info := range files {
|
||||||
|
gotFilenames[i] = info.Name()
|
||||||
|
}
|
||||||
|
sort.Strings(gotFilenames)
|
||||||
|
|
||||||
|
wantFilenames := []string{
|
||||||
|
"lock.json",
|
||||||
|
|
||||||
|
// no "between" because the file in cwd overrides it
|
||||||
|
|
||||||
|
// The mock PurgeUnused doesn't actually purge anything, so the dir
|
||||||
|
// includes both our old and new versions.
|
||||||
|
"terraform-provider-exact_v0.0.1_x4",
|
||||||
|
"terraform-provider-exact_v1.2.3_x4",
|
||||||
|
"terraform-provider-greater_than_v2.3.3_x4",
|
||||||
|
"terraform-provider-greater_than_v2.3.4_x4",
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(gotFilenames, wantFilenames) {
|
||||||
|
t.Errorf("wrong directory contents after upgrade\ngot: %#v\nwant: %#v", gotFilenames, wantFilenames)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestInit_getProviderMissing(t *testing.T) {
|
func TestInit_getProviderMissing(t *testing.T) {
|
||||||
// Create a temporary working directory that is empty
|
// Create a temporary working directory that is empty
|
||||||
td := tempDir(t)
|
td := tempDir(t)
|
||||||
|
|
Loading…
Reference in New Issue