mirror of
https://github.com/hashicorp/packer.git
synced 2025-12-18 23:16:06 -05:00
config: rm mono-component support from config file (#12998)
The global `PACKER_CONFIG` config file was already deprecated from Packer core, but now with 1.11.0 since we remove support for mono-component plugins, we are also removing the capability for that config file to declare them. Instead of silently not using those, Packer will now error with a message pointing to the web docs on how to manage their plugins with the updated workflows for Packer 1.11 and above.
This commit is contained in:
parent
accbe97e1e
commit
8d4a9d66ab
3 changed files with 14 additions and 244 deletions
66
config.go
66
config.go
|
|
@ -9,9 +9,6 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
|
|
@ -41,7 +38,7 @@ func decodeConfig(r io.Reader, c *config) error {
|
|||
}
|
||||
|
||||
// LoadExternalComponentsFromConfig loads plugins defined in RawBuilders, RawProvisioners, and RawPostProcessors.
|
||||
func (c *config) LoadExternalComponentsFromConfig() {
|
||||
func (c *config) LoadExternalComponentsFromConfig() error {
|
||||
// helper to build up list of plugin paths
|
||||
extractPaths := func(m map[string]string) []string {
|
||||
paths := make([]string, 0, len(m))
|
||||
|
|
@ -57,61 +54,20 @@ func (c *config) LoadExternalComponentsFromConfig() {
|
|||
pluginPaths = append(pluginPaths, extractPaths(c.RawBuilders)...)
|
||||
pluginPaths = append(pluginPaths, extractPaths(c.RawPostProcessors)...)
|
||||
|
||||
var externallyUsed = make([]string, 0, len(pluginPaths))
|
||||
for _, pluginPath := range pluginPaths {
|
||||
name, err := c.loadSingleComponent(pluginPath)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("loaded plugin: %s = %s", name, pluginPath)
|
||||
externallyUsed = append(externallyUsed, name)
|
||||
if len(pluginPaths) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(externallyUsed) > 0 {
|
||||
sort.Strings(externallyUsed)
|
||||
log.Printf("using external plugins %v", externallyUsed)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *config) loadSingleComponent(path string) (string, error) {
|
||||
pluginName := filepath.Base(path)
|
||||
|
||||
// On Windows, ignore any plugins that don't end in .exe.
|
||||
// We could do a full PATHEXT parse, but this is probably good enough.
|
||||
if runtime.GOOS == "windows" && strings.ToLower(filepath.Ext(pluginName)) != ".exe" {
|
||||
return "", fmt.Errorf("error loading plugin %q, no exe extension", path)
|
||||
componentList := &strings.Builder{}
|
||||
for _, path := range pluginPaths {
|
||||
fmt.Fprintf(componentList, "- %s\n", path)
|
||||
}
|
||||
|
||||
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 idx := strings.Index(pluginName, "."); idx >= 0 {
|
||||
pluginName = pluginName[:idx]
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(pluginName, "packer-builder-"):
|
||||
pluginName = pluginName[len("packer-builder-"):]
|
||||
c.Plugins.Builders.Set(pluginName, func() (packersdk.Builder, error) {
|
||||
return c.Plugins.Client(path).Builder()
|
||||
})
|
||||
case strings.HasPrefix(pluginName, "packer-post-processor-"):
|
||||
pluginName = pluginName[len("packer-post-processor-"):]
|
||||
c.Plugins.PostProcessors.Set(pluginName, func() (packersdk.PostProcessor, error) {
|
||||
return c.Plugins.Client(path).PostProcessor()
|
||||
})
|
||||
case strings.HasPrefix(pluginName, "packer-provisioner-"):
|
||||
pluginName = pluginName[len("packer-provisioner-"):]
|
||||
c.Plugins.Provisioners.Set(pluginName, func() (packersdk.Provisioner, error) {
|
||||
return c.Plugins.Client(path).Provisioner()
|
||||
})
|
||||
}
|
||||
|
||||
return pluginName, nil
|
||||
return fmt.Errorf("Your configuration file describes some legacy components: \n%s"+
|
||||
"Packer does not support these mono-component plugins anymore.\n"+
|
||||
"Please refer to our Installing Plugins docs for an overview of how to manage installation of local plugins:\n"+
|
||||
"https://developer.hashicorp.com/packer/docs/plugins/install-plugins",
|
||||
componentList.String())
|
||||
}
|
||||
|
||||
// This is a proper packer.BuilderFunc that can be used to load packersdk.Builder
|
||||
|
|
|
|||
188
config_test.go
188
config_test.go
|
|
@ -5,15 +5,9 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
func TestDecodeConfig(t *testing.T) {
|
||||
|
|
@ -42,185 +36,3 @@ func TestDecodeConfig(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLoadExternalComponentsFromConfig(t *testing.T) {
|
||||
packerConfigData, cleanUpFunc, err := generateFakePackerConfigData()
|
||||
if err != nil {
|
||||
t.Fatalf("error encountered while creating fake Packer configuration data %v", err)
|
||||
}
|
||||
defer cleanUpFunc()
|
||||
|
||||
cfg := config{
|
||||
Plugins: &packer.PluginConfig{
|
||||
Builders: packer.MapOfBuilder{},
|
||||
PostProcessors: packer.MapOfPostProcessor{},
|
||||
Provisioners: packer.MapOfProvisioner{},
|
||||
},
|
||||
}
|
||||
|
||||
if err := decodeConfig(strings.NewReader(packerConfigData), &cfg); err != nil {
|
||||
t.Fatalf("error encountered decoding configuration: %v", err)
|
||||
}
|
||||
|
||||
cfg.LoadExternalComponentsFromConfig()
|
||||
|
||||
if len(cfg.Plugins.Builders.List()) != 1 || !cfg.Plugins.Builders.Has("cloud-xyz") {
|
||||
t.Errorf("failed to load external builders; got %v as the resulting config", cfg.Plugins.Builders)
|
||||
}
|
||||
|
||||
if len(cfg.Plugins.PostProcessors.List()) != 1 || !cfg.Plugins.PostProcessors.Has("noop") {
|
||||
t.Errorf("failed to load external post-processors; got %v as the resulting config", cfg.Plugins.PostProcessors)
|
||||
}
|
||||
|
||||
if len(cfg.Plugins.Provisioners.List()) != 1 || !cfg.Plugins.Provisioners.Has("super-shell") {
|
||||
t.Errorf("failed to load external provisioners; got %v as the resulting config", cfg.Plugins.Provisioners)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLoadExternalComponentsFromConfig_onlyProvisioner(t *testing.T) {
|
||||
packerConfigData, cleanUpFunc, err := generateFakePackerConfigData()
|
||||
if err != nil {
|
||||
t.Fatalf("error encountered while creating fake Packer configuration data %v", err)
|
||||
}
|
||||
defer cleanUpFunc()
|
||||
|
||||
cfg := config{
|
||||
Plugins: &packer.PluginConfig{
|
||||
Builders: packer.MapOfBuilder{},
|
||||
PostProcessors: packer.MapOfPostProcessor{},
|
||||
Provisioners: packer.MapOfProvisioner{},
|
||||
},
|
||||
}
|
||||
|
||||
if err := decodeConfig(strings.NewReader(packerConfigData), &cfg); err != nil {
|
||||
t.Fatalf("error encountered decoding configuration: %v", err)
|
||||
}
|
||||
|
||||
/* Let's clear out any custom Builders or PostProcessors that were part of the config.
|
||||
This step does not remove them from disk, it just removes them from of plugins Packer knows about.
|
||||
*/
|
||||
cfg.RawBuilders = nil
|
||||
cfg.RawPostProcessors = nil
|
||||
|
||||
cfg.LoadExternalComponentsFromConfig()
|
||||
|
||||
if len(cfg.Plugins.Builders.List()) != 0 {
|
||||
t.Errorf("loaded external builders when it wasn't supposed to; got %v as the resulting config", cfg.Plugins.Builders)
|
||||
}
|
||||
|
||||
if len(cfg.Plugins.PostProcessors.List()) != 0 {
|
||||
t.Errorf("loaded external post-processors when it wasn't supposed to; got %v as the resulting config", cfg.Plugins.PostProcessors)
|
||||
}
|
||||
|
||||
if len(cfg.Plugins.Provisioners.List()) != 1 || !cfg.Plugins.Provisioners.Has("super-shell") {
|
||||
t.Errorf("failed to load external provisioners; got %v as the resulting config", cfg.Plugins.Provisioners)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSingleComponent(t *testing.T) {
|
||||
|
||||
// .exe will work everyone for testing purpose, but mostly here to help Window's test runs.
|
||||
tmpFile, err := os.CreateTemp(".", "packer-builder-*.exe")
|
||||
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},
|
||||
}
|
||||
|
||||
cfg := config{
|
||||
Plugins: &packer.PluginConfig{
|
||||
Builders: packer.MapOfBuilder{},
|
||||
PostProcessors: packer.MapOfPostProcessor{},
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func generateFakePlugins(dirname string, pluginNames []string) (string, []string, func(), error) {
|
||||
dir, err := os.MkdirTemp("", dirname)
|
||||
if err != nil {
|
||||
return "", nil, nil, fmt.Errorf("failed to create temporary test directory: %v", err)
|
||||
}
|
||||
|
||||
cleanUpFunc := func() {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
var suffix string
|
||||
if runtime.GOOS == "windows" {
|
||||
suffix = ".exe"
|
||||
}
|
||||
|
||||
plugins := make([]string, len(pluginNames))
|
||||
for i, plugin := range pluginNames {
|
||||
plug := filepath.Join(dir, plugin+suffix)
|
||||
plugins[i] = plug
|
||||
_, err := os.Create(plug)
|
||||
if err != nil {
|
||||
cleanUpFunc()
|
||||
return "", nil, nil, fmt.Errorf("failed to create temporary plugin file (%s): %v", plug, err)
|
||||
}
|
||||
}
|
||||
|
||||
return dir, plugins, cleanUpFunc, nil
|
||||
}
|
||||
|
||||
/*
|
||||
generateFakePackerConfigData creates a collection of mock plugins along with a basic packerconfig.
|
||||
|
||||
The return packerConfigData is a valid packerconfig file that can be used for configuring external plugins, cleanUpFunc is a function that should be called for cleaning up any generated mock data.
|
||||
This function will only clean up if there is an error, on successful runs the caller
|
||||
is responsible for cleaning up the data via cleanUpFunc().
|
||||
*/
|
||||
func generateFakePackerConfigData() (packerConfigData string, cleanUpFunc func(), err error) {
|
||||
_, plugins, cleanUpFunc, err := generateFakePlugins("random-testdata",
|
||||
[]string{"packer-builder-cloud-xyz",
|
||||
"packer-provisioner-super-shell",
|
||||
"packer-post-processor-noop"})
|
||||
|
||||
if err != nil {
|
||||
cleanUpFunc()
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
packerConfigData = fmt.Sprintf(`
|
||||
{
|
||||
"PluginMinPort": 10,
|
||||
"PluginMaxPort": 25,
|
||||
"disable_checkpoint": true,
|
||||
"disable_checkpoint_signature": true,
|
||||
"builders": {
|
||||
"cloud-xyz": %q
|
||||
},
|
||||
"provisioners": {
|
||||
"super-shell": %q
|
||||
},
|
||||
"post-processors": {
|
||||
"noop": %q
|
||||
}
|
||||
}`, plugins[0], plugins[1], plugins[2])
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
4
main.go
4
main.go
|
|
@ -381,7 +381,9 @@ func loadConfig() (*config, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
config.LoadExternalComponentsFromConfig()
|
||||
if err := config.LoadExternalComponentsFromConfig(); err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", configFilePath, err)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue