From ee5635722bd8c34cb114c3cbfe80eafcac78e16a Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 14 May 2020 16:22:51 -0700 Subject: [PATCH] enable force, debug, and on-error for hcl2 builds --- command/build.go | 9 +++++++-- hcl2template/types.packer_config.go | 2 +- hcl2template/types.source.go | 16 ++++++++++++++-- main.go | 6 ++++++ packer/core.go | 10 ++++++++++ packer/run_interfaces.go | 2 ++ 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/command/build.go b/command/build.go index c11d4b124..410f1889d 100644 --- a/command/build.go +++ b/command/build.go @@ -135,8 +135,11 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int } builds, diags := packerStarter.GetBuilds(packer.GetBuildsOptions{ - Only: cla.Only, - Except: cla.Except, + Only: cla.Only, + Except: cla.Except, + Debug: cla.Debug, + Force: cla.Force, + OnError: cla.OnError, }) // here, something could have gone wrong but we still want to run valid @@ -186,6 +189,8 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int log.Printf("On error: %v", cla.OnError) // Set the debug and force mode and prepare all the builds + // This is only affects json templates, because HCL2 + // templates have already been prepared in GetBuilds() above. for i := range builds { b := builds[i] log.Printf("Preparing build: %s", b.Name()) diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index 96293eb18..4ca0eba9e 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -311,7 +311,7 @@ func (cfg *PackerConfig) GetBuilds(opts packer.GetBuildsOptions) ([]packer.Build } } - builder, moreDiags, generatedVars := cfg.startBuilder(src, cfg.EvalContext(nil)) + builder, moreDiags, generatedVars := cfg.startBuilder(src, cfg.EvalContext(nil), opts) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue diff --git a/hcl2template/types.source.go b/hcl2template/types.source.go index c44fb2687..dbc5a9724 100644 --- a/hcl2template/types.source.go +++ b/hcl2template/types.source.go @@ -2,6 +2,7 @@ package hcl2template import ( "fmt" + "strconv" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/packer/packer" @@ -38,7 +39,7 @@ func (p *Parser) decodeSource(block *hcl.Block) (*SourceBlock, hcl.Diagnostics) return source, diags } -func (cfg *PackerConfig) startBuilder(source *SourceBlock, ectx *hcl.EvalContext) (packer.Builder, hcl.Diagnostics, []string) { +func (cfg *PackerConfig) startBuilder(source *SourceBlock, ectx *hcl.EvalContext, opts packer.GetBuildsOptions) (packer.Builder, hcl.Diagnostics, []string) { var diags hcl.Diagnostics builder, err := cfg.builderSchemas.Start(source.Type) @@ -57,12 +58,23 @@ func (cfg *PackerConfig) startBuilder(source *SourceBlock, ectx *hcl.EvalContext return nil, diags, nil } - generatedVars, warning, err := builder.Prepare(source.builderVariables(), decoded) + // Note: HCL prepares inside of the Start func, but Json does not. Json + // builds are instead prepared only in command/build.go + // TODO: either make json prepare when plugins are loaded, or make HCL + // prepare at a later step, to make builds from different template types + // easier to reason about. + builderVars := source.builderVariables() + builderVars["packer_debug"] = strconv.FormatBool(opts.Debug) + builderVars["packer_force"] = strconv.FormatBool(opts.Force) + builderVars["packer_on_error"] = opts.OnError + + generatedVars, warning, err := builder.Prepare(builderVars, decoded) moreDiags = warningErrorsToDiags(source.block, warning, err) diags = append(diags, moreDiags...) return builder, diags, generatedVars } +// These variables will populate the PackerConfig inside of the builders. func (source *SourceBlock) builderVariables() map[string]string { return map[string]string{ "packer_build_name": source.Name, diff --git a/main.go b/main.go index 9d13a7f9a..8d4c5ee38 100644 --- a/main.go +++ b/main.go @@ -146,6 +146,11 @@ func wrappedMain() int { runtime.Version(), runtime.GOOS, runtime.GOARCH) + // The config being loaded here is the Packer config -- it defines + // the location of third party builder plugins, plugin ports to use, and + // whether to disable telemetry. It is a global config. + // Do not confuse this config with the .json Packer template which gets + // passed into commands like `packer build` config, err := loadConfig() if err != nil { fmt.Fprintf(os.Stderr, "Error loading configuration: \n\n%s\n", err) @@ -328,6 +333,7 @@ func loadConfig() (*config, error) { } defer f.Close() + // This loads a json config, defined in packer/config.go if err := decodeConfig(f, &config); err != nil { return nil, err } diff --git a/packer/core.go b/packer/core.go index 5faf56ae7..fcf72a6c5 100644 --- a/packer/core.go +++ b/packer/core.go @@ -199,6 +199,8 @@ func (c *Core) generateCoreBuildProvisioner(rawP *template.Provisioner, rawName return cbp, nil } +// This is used for json templates to launch the build plugins. +// They will be prepared via b.Prepare() later. func (c *Core) GetBuilds(opts GetBuildsOptions) ([]Build, hcl.Diagnostics) { buildNames := c.BuildNames(opts.Only, opts.Except) builds := []Build{} @@ -225,6 +227,12 @@ func (c *Core) Build(n string) (Build, error) { if !ok { return nil, fmt.Errorf("no such build found: %s", n) } + // BuilderStore = config.Builders, gathered in loadConfig() in main.go + // For reference, the builtin BuilderStore is generated in + // packer/config.go in the Discover() func. + + // the Start command launches the builder plugin of the given type without + // calling Prepare() or passing any build-specific details. builder, err := c.components.BuilderStore.Start(configBuilder.Type) if err != nil { return nil, fmt.Errorf( @@ -315,6 +323,8 @@ func (c *Core) Build(n string) (Build, error) { // TODO hooks one day + // Return a structure that contains the plugins, their types, variables, and + // the raw builder config loaded from the json template return &CoreBuild{ Type: n, Builder: builder, diff --git a/packer/run_interfaces.go b/packer/run_interfaces.go index 8403a0b53..02048f6df 100644 --- a/packer/run_interfaces.go +++ b/packer/run_interfaces.go @@ -6,6 +6,8 @@ type GetBuildsOptions struct { // Get builds except the ones that match with except and with only the ones // that match with Only. When those are empty everything matches. Except, Only []string + Debug, Force bool + OnError string } type BuildGetter interface {