config: Update loading of packerconfig to only log when a plugin is loaded

Before this change loading of a packerconfig would display `loaded
plugin ...` for any plugin defined in the packerconfig - even if it
didn't exist on disk. This change updates how plugins defined in
packerconfig are loaded to ensure that only successfully loaded plugins
get the lovely message `loaded plugin ...`. For any plugin that fails to
load Packer will log that it failed to load the plugin and continue
processing any other defined plugins.

* Add a test to ensure loadSingleComponent errors when plugin does not
exists
This commit is contained in:
nywilken 2020-01-17 13:33:51 -05:00
parent 39c25b2c66
commit c93a076698
2 changed files with 57 additions and 13 deletions

View File

@ -61,10 +61,14 @@ func (c *config) LoadExternalComponentsFromConfig() {
var externallyUsed = make([]string, 0, len(pluginPaths)) var externallyUsed = make([]string, 0, len(pluginPaths))
for _, pluginPath := range pluginPaths { for _, pluginPath := range pluginPaths {
if name, ok := c.loadExternalComponent(pluginPath); ok { name, err := c.loadSingleComponent(pluginPath)
log.Printf("[DEBUG] Loaded plugin: %s = %s", name, pluginPath) if err != nil {
externallyUsed = append(externallyUsed, name) log.Print(err)
continue
} }
log.Printf("loaded plugin: %s = %s", name, pluginPath)
externallyUsed = append(externallyUsed, name)
} }
if len(externallyUsed) > 0 { if len(externallyUsed) > 0 {
@ -73,14 +77,17 @@ func (c *config) LoadExternalComponentsFromConfig() {
} }
} }
func (c *config) loadExternalComponent(path string) (string, bool) { func (c *config) loadSingleComponent(path string) (string, error) {
pluginName := filepath.Base(path) pluginName := filepath.Base(path)
// On Windows, ignore any plugins that don't end in .exe. // On Windows, ignore any plugins that don't end in .exe.
// We could do a full PATHEXT parse, but this is probably good enough. // We could do a full PATHEXT parse, but this is probably good enough.
if runtime.GOOS == "windows" && strings.ToLower(filepath.Ext(pluginName)) != ".exe" { if runtime.GOOS == "windows" && strings.ToLower(filepath.Ext(pluginName)) != ".exe" {
log.Printf("[DEBUG] Ignoring plugin %s, no exe extension", path) return "", fmt.Errorf("error loading plugin %q, no exe extension", path)
return "", false }
if _, err := os.Stat(path); err != nil {
return "", fmt.Errorf("error loading plugin %q: %s", path, err)
} }
// If the filename has a ".", trim up to there // If the filename has a ".", trim up to there
@ -106,7 +113,7 @@ func (c *config) loadExternalComponent(path string) (string, bool) {
} }
} }
return pluginName, true return pluginName, nil
} }
// Discover discovers plugins. // Discover discovers plugins.

View File

@ -63,13 +63,14 @@ func TestLoadExternalComponentsFromConfig(t *testing.T) {
t.Errorf("failed to load external builders; got %v as the resulting config", cfg.Builders) t.Errorf("failed to load external builders; got %v as the resulting config", cfg.Builders)
} }
if len(cfg.PostProcessors) != 1 || !cfg.PostProcessors.Has("noop") {
t.Errorf("failed to load external post-processors; got %v as the resulting config", cfg.PostProcessors)
}
if len(cfg.Provisioners) != 1 || !cfg.Provisioners.Has("super-shell") { if len(cfg.Provisioners) != 1 || !cfg.Provisioners.Has("super-shell") {
t.Errorf("failed to load external provisioners; got %v as the resulting config", cfg.Provisioners) t.Errorf("failed to load external provisioners; got %v as the resulting config", cfg.Provisioners)
} }
if len(cfg.PostProcessors) != 1 || !cfg.PostProcessors.Has("noop") {
t.Errorf("failed to load external post-processors; got %v as the resulting config", cfg.PostProcessors)
}
} }
func TestLoadExternalComponentsFromConfig_onlyProvisioner(t *testing.T) { func TestLoadExternalComponentsFromConfig_onlyProvisioner(t *testing.T) {
@ -94,17 +95,53 @@ func TestLoadExternalComponentsFromConfig_onlyProvisioner(t *testing.T) {
cfg.LoadExternalComponentsFromConfig() cfg.LoadExternalComponentsFromConfig()
if len(cfg.Builders) != 0 || cfg.Builders.Has("cloud-xyz") { if len(cfg.Builders) != 0 {
t.Errorf("loaded external builders when it wasn't supposed to; got %v as the resulting config", cfg.Builders) t.Errorf("loaded external builders when it wasn't supposed to; got %v as the resulting config", cfg.Builders)
} }
if len(cfg.PostProcessors) != 0 {
t.Errorf("loaded external post-processors when it wasn't supposed to; got %v as the resulting config", cfg.PostProcessors)
}
if len(cfg.Provisioners) != 1 || !cfg.Provisioners.Has("super-shell") { if len(cfg.Provisioners) != 1 || !cfg.Provisioners.Has("super-shell") {
t.Errorf("failed to load external provisioners; got %v as the resulting config", cfg.Provisioners) t.Errorf("failed to load external provisioners; got %v as the resulting config", cfg.Provisioners)
} }
}
if len(cfg.PostProcessors) != 0 || cfg.PostProcessors.Has("noop") { func TestLoadSingleComponent(t *testing.T) {
t.Errorf("loaded external post-processors when it wasn't supposed to; got %v as the resulting config", cfg.PostProcessors)
tmpFile, err := ioutil.TempFile(".", "packer-builder-")
if err != nil {
t.Fatalf("failed to create test file with error: %s", err)
} }
defer os.Remove(tmpFile.Name())
tt := []struct {
pluginPath string
errorExpected bool
}{
{pluginPath: tmpFile.Name(), errorExpected: false},
{pluginPath: "./non-existing-file", errorExpected: true},
}
var cfg config
cfg.Builders = packer.MapOfBuilder{}
cfg.PostProcessors = packer.MapOfPostProcessor{}
cfg.Provisioners = packer.MapOfProvisioner{}
for _, tc := range tt {
tc := tc
_, err := cfg.loadSingleComponent(tc.pluginPath)
if tc.errorExpected && err == nil {
t.Errorf("expected loadSingleComponent(%s) to error but it didn't", tc.pluginPath)
continue
}
if err != nil && !tc.errorExpected {
t.Errorf("expected loadSingleComponent(%s) to load properly but got an error: %v", tc.pluginPath, err)
}
}
} }
/* generateFakePackerConfigData creates a collection of mock plugins along with a basic packerconfig. /* generateFakePackerConfigData creates a collection of mock plugins along with a basic packerconfig.