From a2930bda4fb9863687bd614ea3b875604d1acda0 Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Tue, 11 Jul 2023 15:41:37 -0400 Subject: [PATCH] packer: warn on bundled plugins usage Since bundled plugins will be removed in an upcoming version of Packer, this commit adds a new warning message whenever a template uses one such plugin. This warning has been implemented on build, validate, console and the inspect subcommands. In addition to warning about the upcoming change and potential issue this will cause, this warning message proposes solutions to the user so they know what they'll have to do in order not to rely on those bundled plugins later. --- acctest/plugin/bundled_plugin_test.go | 181 ++++++++++++++++++ .../test-fixtures/basic_amazon_bundled.json | 10 + .../basic_amazon_bundled.pkr.hcl | 11 ++ ...basic_amazon_with_required_plugins.pkr.hcl | 20 ++ command/build.go | 10 +- command/meta.go | 175 +++++++++++++++++ command/validate.go | 10 +- command/vendored_plugins.go | 168 ++++++++++++++++ config.go | 4 + hcl2template/parser.go | 15 +- hcl2template/plugin.go | 2 +- packer/core.go | 6 + packer/run_interfaces.go | 7 + 13 files changed, 603 insertions(+), 16 deletions(-) create mode 100644 acctest/plugin/bundled_plugin_test.go create mode 100644 acctest/plugin/test-fixtures/basic_amazon_bundled.json create mode 100644 acctest/plugin/test-fixtures/basic_amazon_bundled.pkr.hcl create mode 100644 acctest/plugin/test-fixtures/basic_amazon_with_required_plugins.pkr.hcl diff --git a/acctest/plugin/bundled_plugin_test.go b/acctest/plugin/bundled_plugin_test.go new file mode 100644 index 000000000..e9308a598 --- /dev/null +++ b/acctest/plugin/bundled_plugin_test.go @@ -0,0 +1,181 @@ +package plugin + +import ( + _ "embed" + "errors" + "fmt" + "os" + "os/exec" + "strings" + "testing" + + "github.com/hashicorp/go-multierror" + amazonacc "github.com/hashicorp/packer-plugin-amazon/builder/ebs/acceptance" + "github.com/hashicorp/packer-plugin-sdk/acctest" + "github.com/hashicorp/packer/hcl2template/addrs" +) + +//go:embed test-fixtures/basic_amazon_bundled.pkr.hcl +var basicAmazonBundledEbsTemplate string + +func TestAccBuildBundledPlugins(t *testing.T) { + plugin := addrs.Plugin{ + Hostname: "github.com", + Namespace: "hashicorp", + Type: "amazon", + } + testCase := &acctest.PluginTestCase{ + Name: "amazon-ebs_bundled_test", + Setup: func() error { + return cleanupPluginInstallation(plugin) + }, + Teardown: func() error { + helper := amazonacc.AMIHelper{ + Region: "us-east-1", + Name: "packer-plugin-bundled-amazon-ebs-test", + } + return helper.CleanUpAmi() + }, + Template: basicAmazonBundledEbsTemplate, + Type: "amazon-ebs", + Init: false, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + + rawLogs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("failed to read logs: %s", err) + } + + var errs error + + logs := string(rawLogs) + + if !strings.Contains(logs, "Warning: Bundled plugins used") { + errs = multierror.Append(errs, errors.New("expected warning about bundled plugins used, did not find it")) + } + + if !strings.Contains(logs, "Then run 'packer init' to manage installation of the plugins") { + errs = multierror.Append(errs, errors.New("expected suggestion about packer init in logs, did not find it.")) + } + + return errs + }, + } + + acctest.TestPlugin(t, testCase) +} + +//go:embed test-fixtures/basic_amazon_with_required_plugins.pkr.hcl +var basicAmazonRequiredPluginEbsTemplate string + +func TestAccBuildBundledPluginsWithRequiredPlugins(t *testing.T) { + plugin := addrs.Plugin{ + Hostname: "github.com", + Namespace: "hashicorp", + Type: "amazon", + } + testCase := &acctest.PluginTestCase{ + Name: "amazon-ebs_with_required_plugins_test", + Setup: func() error { + return cleanupPluginInstallation(plugin) + }, + Teardown: func() error { + helper := amazonacc.AMIHelper{ + Region: "us-east-1", + Name: "packer-plugin-required-plugin-amazon-ebs-test", + } + return helper.CleanUpAmi() + }, + Template: basicAmazonRequiredPluginEbsTemplate, + Type: "amazon-ebs", + Init: false, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 1 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + + rawLogs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("failed to read logs: %s", err) + } + + var errs error + + logs := string(rawLogs) + + if strings.Contains(logs, "Warning: Bundled plugins used") { + errs = multierror.Append(errs, errors.New("did not expect warning about bundled plugins used")) + } + + if !strings.Contains(logs, "Missing plugins") { + errs = multierror.Append(errs, errors.New("expected error about plugins required and not installed, did not find it")) + } + + return errs + }, + } + + acctest.TestPlugin(t, testCase) +} + +//go:embed test-fixtures/basic_amazon_bundled.json +var basicAmazonBundledEbsTemplateJSON string + +func TestAccBuildBundledPluginsJSON(t *testing.T) { + plugin := addrs.Plugin{ + Hostname: "github.com", + Namespace: "hashicorp", + Type: "amazon", + } + testCase := &acctest.PluginTestCase{ + Name: "amazon-ebs_bundled_test_json", + Setup: func() error { + return cleanupPluginInstallation(plugin) + }, + Teardown: func() error { + helper := amazonacc.AMIHelper{ + Region: "us-east-1", + Name: "packer-plugin-bundled-amazon-ebs-test-json", + } + return helper.CleanUpAmi() + }, + Template: basicAmazonBundledEbsTemplateJSON, + Type: "amazon-ebs", + Init: false, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + + rawLogs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("failed to read logs: %s", err) + } + + var errs error + + logs := string(rawLogs) + + if !strings.Contains(logs, "Warning: Bundled plugins used") { + errs = multierror.Append(errs, errors.New("expected warning about bundled plugins, did not find it.")) + } + + if !strings.Contains(logs, "plugins with the 'packer plugins install' command") { + errs = multierror.Append(errs, errors.New("expected suggestion about packer plugins install in logs, did not find it.")) + } + + return errs + }, + } + + acctest.TestPlugin(t, testCase) +} diff --git a/acctest/plugin/test-fixtures/basic_amazon_bundled.json b/acctest/plugin/test-fixtures/basic_amazon_bundled.json new file mode 100644 index 000000000..f674cd130 --- /dev/null +++ b/acctest/plugin/test-fixtures/basic_amazon_bundled.json @@ -0,0 +1,10 @@ +{ + "builders": [{ + "type": "amazon-ebs", + "region": "us-east-1", + "instance_type": "m3.medium", + "source_ami": "ami-76b2a71e", + "ssh_username": "ubuntu", + "ami_name": "packer-plugin-bundled-amazon-ebs-test-json" + }] +} diff --git a/acctest/plugin/test-fixtures/basic_amazon_bundled.pkr.hcl b/acctest/plugin/test-fixtures/basic_amazon_bundled.pkr.hcl new file mode 100644 index 000000000..c17a09df0 --- /dev/null +++ b/acctest/plugin/test-fixtures/basic_amazon_bundled.pkr.hcl @@ -0,0 +1,11 @@ +source "amazon-ebs" "basic-test" { + region = "us-east-1" + instance_type = "m3.medium" + source_ami = "ami-76b2a71e" + ssh_username = "ubuntu" + ami_name = "packer-plugin-bundled-amazon-ebs-test" +} + +build { + sources = ["source.amazon-ebs.basic-test"] +} diff --git a/acctest/plugin/test-fixtures/basic_amazon_with_required_plugins.pkr.hcl b/acctest/plugin/test-fixtures/basic_amazon_with_required_plugins.pkr.hcl new file mode 100644 index 000000000..f9ba5a55b --- /dev/null +++ b/acctest/plugin/test-fixtures/basic_amazon_with_required_plugins.pkr.hcl @@ -0,0 +1,20 @@ +packer { + required_plugins { + amazon = { + source = "github.com/hashicorp/amazon", + version = "~> 1" + } + } +} + +source "amazon-ebs" "basic-test" { + region = "us-east-1" + instance_type = "m3.medium" + source_ami = "ami-76b2a71e" + ssh_username = "ubuntu" + ami_name = "packer-plugin-bundled-amazon-ebs-test" +} + +build { + sources = ["source.amazon-ebs.basic-test"] +} diff --git a/command/build.go b/command/build.go index b707fe22d..842938adc 100644 --- a/command/build.go +++ b/command/build.go @@ -87,7 +87,15 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int return ret } - diags := packerStarter.Initialize(packer.InitializeOptions{}) + diags := packerStarter.DetectPluginBinaries() + ret = writeDiags(c.Ui, nil, diags) + if ret != 0 { + return ret + } + + diags = packerStarter.Initialize(packer.InitializeOptions{}) + bundledDiags := c.DetectBundledPlugins(packerStarter) + diags = append(bundledDiags, diags...) ret = writeDiags(c.Ui, nil, diags) if ret != 0 { return ret diff --git a/command/meta.go b/command/meta.go index 99123fd8e..1579d1522 100644 --- a/command/meta.go +++ b/command/meta.go @@ -9,7 +9,9 @@ import ( "fmt" "io" "os" + "strings" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclparse" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" "github.com/hashicorp/packer-plugin-sdk/template" @@ -179,3 +181,176 @@ func (m *Meta) GetConfigFromJSON(cla *MetaArgs) (packer.Handler, int) { } return core, ret } + +func (m *Meta) DetectBundledPlugins(handler packer.Handler) hcl.Diagnostics { + var plugins []string + + switch h := handler.(type) { + case *packer.Core: + plugins = m.detectBundledPluginsJSON(h) + case *hcl2template.PackerConfig: + plugins = m.detectBundledPluginsHCL2(handler.(*hcl2template.PackerConfig)) + } + + if len(plugins) == 0 { + return nil + } + + buf := &strings.Builder{} + buf.WriteString("This template relies on the use of plugins bundled into the Packer binary.\n") + buf.WriteString("The practice of bundling external plugins into Packer will be removed in an upcoming version.\n\n") + switch h := handler.(type) { + case *packer.Core: + buf.WriteString("To remove this warning and ensure builds keep working you can install these external plugins with the 'packer plugins install' command\n\n") + + for _, plugin := range plugins { + fmt.Fprintf(buf, "* packer plugins install %s\n", plugin) + } + + buf.WriteString("\nAlternatively, if you upgrade your templates to HCL2, you can use 'packer init' with a 'required_plugins' block to automatically install external plugins.\n\n") + fmt.Fprintf(buf, "You can try HCL2 by running 'packer hcl2_upgrade %s'", h.Template.Path) + case *hcl2template.PackerConfig: + buf.WriteString("To remove this warning, add the following section to your template:\n") + buf.WriteString(m.fixRequiredPlugins(h)) + buf.WriteString("\nThen run 'packer init' to manage installation of the plugins") + } + + return hcl.Diagnostics{ + &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: "Bundled plugins used", + Detail: buf.String(), + }, + } +} + +func (m *Meta) detectBundledPluginsJSON(core *packer.Core) []string { + bundledPlugins := map[string]struct{}{} + + tmpl := core.Template + if tmpl == nil { + panic("No template parsed. This is a Packer bug which should be reported, please open an issue on the project's issue tracker.") + } + + for _, b := range tmpl.Builders { + builderType := fmt.Sprintf("packer-builder-%s", b.Type) + if bundledStatus[builderType] { + bundledPlugins[builderType] = struct{}{} + } + } + + for _, p := range tmpl.Provisioners { + provisionerType := fmt.Sprintf("packer-provisioner-%s", p.Type) + if bundledStatus[provisionerType] { + bundledPlugins[provisionerType] = struct{}{} + } + } + + for _, pps := range tmpl.PostProcessors { + for _, pp := range pps { + postProcessorType := fmt.Sprintf("packer-post-processor-%s", pp.Type) + if bundledStatus[postProcessorType] { + bundledPlugins[postProcessorType] = struct{}{} + } + } + } + + return compileBundledPluginList(bundledPlugins) +} + +var knownPluginPrefixes = map[string]string{ + "amazon": "github.com/hashicorp/amazon", + "ansible": "github.com/hashicorp/ansible", + "azure": "github.com/hashicorp/azure", + "docker": "github.com/hashicorp/docker", + "googlecompute": "github.com/hashicorp/googlecompute", + "qemu": "github.com/hashicorp/qemu", + "vagrant": "github.com/hashicorp/vagrant", + "vmware": "github.com/hashicorp/vmware", + "vsphere": "github.com/hashicorp/vsphere", +} + +func (m *Meta) fixRequiredPlugins(config *hcl2template.PackerConfig) string { + plugins := map[string]struct{}{} + + for _, b := range config.Builds { + for _, b := range b.Sources { + for prefix, plugin := range knownPluginPrefixes { + if strings.HasPrefix(b.Type, prefix) { + plugins[plugin] = struct{}{} + } + } + } + + for _, p := range b.ProvisionerBlocks { + for prefix, plugin := range knownPluginPrefixes { + if strings.HasPrefix(p.PType, prefix) { + plugins[plugin] = struct{}{} + } + } + } + + for _, pps := range b.PostProcessorsLists { + for _, pp := range pps { + for prefix, plugin := range knownPluginPrefixes { + if strings.HasPrefix(pp.PType, prefix) { + plugins[plugin] = struct{}{} + } + } + } + } + } + + for _, ds := range config.Datasources { + for prefix, plugin := range knownPluginPrefixes { + if strings.HasPrefix(ds.Type, prefix) { + plugins[plugin] = struct{}{} + } + } + } + + retPlugins := make([]string, 0, len(plugins)) + for plugin := range plugins { + retPlugins = append(retPlugins, plugin) + } + + return generateRequiredPluginsBlock(retPlugins) +} + +func (m *Meta) detectBundledPluginsHCL2(config *hcl2template.PackerConfig) []string { + bundledPlugins := map[string]struct{}{} + + for _, b := range config.Builds { + for _, src := range b.Sources { + builderType := fmt.Sprintf("packer-builder-%s", src.Type) + if bundledStatus[builderType] { + bundledPlugins[builderType] = struct{}{} + } + } + + for _, p := range b.ProvisionerBlocks { + provisionerType := fmt.Sprintf("packer-provisioner-%s", p.PType) + if bundledStatus[provisionerType] { + bundledPlugins[provisionerType] = struct{}{} + } + } + + for _, pps := range b.PostProcessorsLists { + for _, pp := range pps { + postProcessorType := fmt.Sprintf("packer-post-processor-%s", pp.PType) + if bundledStatus[postProcessorType] { + bundledPlugins[postProcessorType] = struct{}{} + } + } + } + } + + for _, ds := range config.Datasources { + dsType := fmt.Sprintf("packer-datasource-%s", ds.Type) + if bundledStatus[dsType] { + bundledPlugins[dsType] = struct{}{} + } + } + + return compileBundledPluginList(bundledPlugins) +} diff --git a/command/validate.go b/command/validate.go index 1bc4cc1d7..2b7e2107b 100644 --- a/command/validate.go +++ b/command/validate.go @@ -65,9 +65,17 @@ func (c *ValidateCommand) RunContext(ctx context.Context, cla *ValidateArgs) int return 0 } - diags := packerStarter.Initialize(packer.InitializeOptions{ + diags := packerStarter.DetectPluginBinaries() + ret = writeDiags(c.Ui, nil, diags) + if ret != 0 { + return ret + } + + diags = packerStarter.Initialize(packer.InitializeOptions{ SkipDatasourcesExecution: !cla.EvaluateDatasources, }) + bundledDiags := c.DetectBundledPlugins(packerStarter) + diags = append(bundledDiags, diags...) ret = writeDiags(c.Ui, nil, diags) if ret != 0 { return ret diff --git a/command/vendored_plugins.go b/command/vendored_plugins.go index 0718b91a7..d6e5f8363 100644 --- a/command/vendored_plugins.go +++ b/command/vendored_plugins.go @@ -4,6 +4,10 @@ package command import ( + "fmt" + "log" + "strings" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" // Previously core-bundled components, split into their own plugins but @@ -102,6 +106,170 @@ var VendoredPostProcessors = map[string]packersdk.PostProcessor{ "vsphere": new(vspherepostprocessor.PostProcessor), } +// bundledStatus is used to know if one of the bundled components is loaded from +// an external plugin, or from the bundled plugins. +// +// We keep track of this to produce a warning if a user relies on one +// such plugin, as they will be removed in a later version of Packer. +var bundledStatus = map[string]bool{ + "packer-builder-amazon-ebs": false, + "packer-builder-amazon-chroot": false, + "packer-builder-amazon-ebssurrogate": false, + "packer-builder-amazon-ebsvolume": false, + "packer-builder-amazon-instance": false, + "packer-post-processor-amazon-import": false, + "packer-datasource-amazon-ami": false, + "packer-datasource-amazon-secretsmanager": false, + + "packer-provisioner-ansible": false, + "packer-provisioner-ansible-local": false, + + "packer-provisioner-azure-dtlartifact": false, + "packer-builder-azure-arm": false, + "packer-builder-azure-chroot": false, + "packer-builder-azure-dtl": false, + + "packer-builder-docker": false, + "packer-post-processor-docker-import": false, + "packer-post-processor-docker-push": false, + "packer-post-processor-docker-save": false, + "packer-post-processor-docker-tag": false, + + "packer-builder-googlecompute": false, + "packer-post-processor-googlecompute-export": false, + "packer-post-processor-googlecompute-import": false, + + "packer-builder-qemu": false, + + "packer-builder-vagrant": false, + "packer-post-processor-vagrant": false, + "packer-post-processor-vagrant-cloud": false, + + "packer-builder-virtualbox-iso": false, + "packer-builder-virtualbox-ovf": false, + "packer-builder-virtualbox-vm": false, + + "packer-builder-vmware-iso": false, + "packer-builder-vmware-vmx": false, + + "packer-builder-vsphere-clone": false, + "packer-builder-vsphere-iso": false, + "packer-post-processor-vsphere-template": false, + "packer-post-processor-vsphere": false, +} + +// TrackBundledPlugin marks a component as loaded from Packer's bundled plugins +// instead of from an externally loaded plugin. +// +// NOTE: `pluginName' must be in the format `packer--' +func TrackBundledPlugin(pluginName string) { + _, exists := bundledStatus[pluginName] + if !exists { + return + } + + bundledStatus[pluginName] = true +} + +var componentPluginMap = map[string]string{ + "packer-builder-amazon-ebs": "github.com/hashicorp/amazon", + "packer-builder-amazon-chroot": "github.com/hashicorp/amazon", + "packer-builder-amazon-ebssurrogate": "github.com/hashicorp/amazon", + "packer-builder-amazon-ebsvolume": "github.com/hashicorp/amazon", + "packer-builder-amazon-instance": "github.com/hashicorp/amazon", + "packer-post-processor-amazon-import": "github.com/hashicorp/amazon", + "packer-datasource-amazon-ami": "github.com/hashicorp/amazon", + "packer-datasource-amazon-secretsmanager": "github.com/hashicorp/amazon", + + "packer-provisioner-ansible": "github.com/hashicorp/ansible", + "packer-provisioner-ansible-local": "github.com/hashicorp/ansible", + + "packer-provisioner-azure-dtlartifact": "github.com/hashicorp/azure", + "packer-builder-azure-arm": "github.com/hashicorp/azure", + "packer-builder-azure-chroot": "github.com/hashicorp/azure", + "packer-builder-azure-dtl": "github.com/hashicorp/azure", + + "packer-builder-docker": "github.com/hashicorp/docker", + "packer-post-processor-docker-import": "github.com/hashicorp/docker", + "packer-post-processor-docker-push": "github.com/hashicorp/docker", + "packer-post-processor-docker-save": "github.com/hashicorp/docker", + "packer-post-processor-docker-tag": "github.com/hashicorp/docker", + + "packer-builder-googlecompute": "github.com/hashicorp/googlecompute", + "packer-post-processor-googlecompute-export": "github.com/hashicorp/googlecompute", + "packer-post-processor-googlecompute-import": "github.com/hashicorp/googlecompute", + + "packer-builder-qemu": "github.com/hashicorp/qemu", + + "packer-builder-vagrant": "github.com/hashicorp/vagrant", + "packer-post-processor-vagrant": "github.com/hashicorp/vagrant", + "packer-post-processor-vagrant-cloud": "github.com/hashicorp/vagrant", + + "packer-builder-virtualbox-iso": "github.com/hashicorp/virtualbox", + "packer-builder-virtualbox-ovf": "github.com/hashicorp/virtualbox", + "packer-builder-virtualbox-vm": "github.com/hashicorp/virtualbox", + + "packer-builder-vmware-iso": "github.com/hashicorp/vmware", + "packer-builder-vmware-vmx": "github.com/hashicorp/vmware", + + "packer-builder-vsphere-clone": "github.com/hashicorp/vsphere", + "packer-builder-vsphere-iso": "github.com/hashicorp/vsphere", + "packer-post-processor-vsphere-template": "github.com/hashicorp/vsphere", + "packer-post-processor-vsphere": "github.com/hashicorp/vsphere", +} + +// compileBundledPluginList returns a list of plugins to import in a config +// +// This only works on bundled plugins and serves as a way to inform users that +// they should not rely on a bundled plugin anymore, but give them recommendations +// on how to manage those plugins instead. +func compileBundledPluginList(componentMap map[string]struct{}) []string { + plugins := map[string]struct{}{} + for component := range componentMap { + plugin, ok := componentPluginMap[component] + if !ok { + log.Printf("Unknown bundled plugin component: %q", component) + continue + } + + plugins[plugin] = struct{}{} + } + + pluginList := make([]string, 0, len(plugins)) + for plugin := range plugins { + pluginList = append(pluginList, plugin) + } + + return pluginList +} + +func generateRequiredPluginsBlock(plugins []string) string { + if len(plugins) == 0 { + return "" + } + + buf := &strings.Builder{} + buf.WriteString(` +packer { + required_plugins {`) + + for _, plugin := range plugins { + pluginName := strings.Replace(plugin, "github.com/hashicorp/", "", 1) + fmt.Fprintf(buf, ` + %s = { + source = %q + version = "~> 1" + }`, pluginName, plugin) + } + + buf.WriteString(` + } +} +`) + + return buf.String() +} + // Upon init lets load up any plugins that were vendored manually into the default // set of plugins. func init() { diff --git a/config.go b/config.go index 6b59b98fe..af679dd8e 100644 --- a/config.go +++ b/config.go @@ -153,6 +153,7 @@ func (c *config) discoverInternalComponents() error { for builder := range command.Builders { builder := builder if !c.Plugins.Builders.Has(builder) { + command.TrackBundledPlugin(fmt.Sprintf("packer-builder-%s", builder)) bin := fmt.Sprintf("%s%splugin%spacker-builder-%s", packerPath, PACKERSPACE, PACKERSPACE, builder) c.Plugins.Builders.Set(builder, func() (packersdk.Builder, error) { @@ -164,6 +165,7 @@ func (c *config) discoverInternalComponents() error { for provisioner := range command.Provisioners { provisioner := provisioner if !c.Plugins.Provisioners.Has(provisioner) { + command.TrackBundledPlugin(fmt.Sprintf("packer-provisioner-%s", provisioner)) bin := fmt.Sprintf("%s%splugin%spacker-provisioner-%s", packerPath, PACKERSPACE, PACKERSPACE, provisioner) c.Plugins.Provisioners.Set(provisioner, func() (packersdk.Provisioner, error) { @@ -175,6 +177,7 @@ func (c *config) discoverInternalComponents() error { for postProcessor := range command.PostProcessors { postProcessor := postProcessor if !c.Plugins.PostProcessors.Has(postProcessor) { + command.TrackBundledPlugin(fmt.Sprintf("packer-post-processor-%s", postProcessor)) bin := fmt.Sprintf("%s%splugin%spacker-post-processor-%s", packerPath, PACKERSPACE, PACKERSPACE, postProcessor) c.Plugins.PostProcessors.Set(postProcessor, func() (packersdk.PostProcessor, error) { @@ -186,6 +189,7 @@ func (c *config) discoverInternalComponents() error { for dataSource := range command.Datasources { dataSource := dataSource if !c.Plugins.DataSources.Has(dataSource) { + command.TrackBundledPlugin(fmt.Sprintf("packer-datasource-%s", dataSource)) bin := fmt.Sprintf("%s%splugin%spacker-datasource-%s", packerPath, PACKERSPACE, PACKERSPACE, dataSource) c.Plugins.DataSources.Set(dataSource, func() (packersdk.Datasource, error) { diff --git a/hcl2template/parser.go b/hcl2template/parser.go index 2246131fa..a724bb807 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -308,19 +308,8 @@ func filterVarsFromLogs(inputOrLocal Variables) { } func (cfg *PackerConfig) Initialize(opts packer.InitializeOptions) hcl.Diagnostics { - var diags hcl.Diagnostics - - // enable packer to start plugins requested in required_plugins. - moreDiags := cfg.detectPluginBinaries() - diags = append(diags, moreDiags...) - if moreDiags.HasErrors() { - return diags - } - - moreDiags = cfg.InputVariables.ValidateValues() - diags = append(diags, moreDiags...) - moreDiags = cfg.LocalVariables.ValidateValues() - diags = append(diags, moreDiags...) + diags := cfg.InputVariables.ValidateValues() + diags = append(diags, cfg.LocalVariables.ValidateValues()...) diags = append(diags, cfg.evaluateDatasources(opts.SkipDatasourcesExecution)...) diags = append(diags, checkForDuplicateLocalDefinition(cfg.LocalBlocks)...) diags = append(diags, cfg.evaluateLocalVariables(cfg.LocalBlocks)...) diff --git a/hcl2template/plugin.go b/hcl2template/plugin.go index 1c32ef777..4a5c01866 100644 --- a/hcl2template/plugin.go +++ b/hcl2template/plugin.go @@ -55,7 +55,7 @@ func (cfg *PackerConfig) PluginRequirements() (plugingetter.Requirements, hcl.Di return reqs, diags } -func (cfg *PackerConfig) detectPluginBinaries() hcl.Diagnostics { +func (cfg *PackerConfig) DetectPluginBinaries() hcl.Diagnostics { opts := plugingetter.ListInstallationsOptions{ FromFolders: cfg.parser.PluginConfig.KnownPluginFolders, BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{ diff --git a/packer/core.go b/packer/core.go index 4d62cce6b..b711af080 100644 --- a/packer/core.go +++ b/packer/core.go @@ -132,6 +132,12 @@ func NewCore(c *CoreConfig) *Core { return core } +// DetectPluginBinaries is used to load required plugins from the template, +// since it is unsupported in JSON, this is essentially a no-op. +func (c *Core) DetectPluginBinaries() hcl.Diagnostics { + return nil +} + func (c *Core) Initialize(_ InitializeOptions) hcl.Diagnostics { err := c.initialize() if err != nil { diff --git a/packer/run_interfaces.go b/packer/run_interfaces.go index 5bf115152..253998c20 100644 --- a/packer/run_interfaces.go +++ b/packer/run_interfaces.go @@ -40,6 +40,12 @@ type InitializeOptions struct { SkipDatasourcesExecution bool } +type PluginBinaryDetector interface { + // DetectPluginBinaries is used only for HCL2 templates, and loads required + // plugins if specified. + DetectPluginBinaries() hcl.Diagnostics +} + // The Handler handles all Packer things. This interface reflects the Packer // commands, ex: init, console ( evaluate ), fix config, inspect config, etc. To // run a build we will start the builds and then the core of Packer handles @@ -53,6 +59,7 @@ type Handler interface { BuildGetter ConfigFixer ConfigInspector + PluginBinaryDetector } //go:generate enumer -type FixConfigMode