Avoid calling CoreBuild.Prepare(...) for HCL2 templates (#8742)

This commit is contained in:
Sylvia Moss 2020-02-14 17:39:32 +01:00 committed by GitHub
parent 7254b04129
commit 2981fd627d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 25 deletions

View File

@ -49,7 +49,7 @@ func (p *Parser) decodePostProcessor(block *hcl.Block) (*PostProcessorBlock, hcl
return postProcessor, diags
}
func (p *Parser) startPostProcessor(pp *PostProcessorBlock, ectx *hcl.EvalContext) (packer.PostProcessor, hcl.Diagnostics) {
func (p *Parser) startPostProcessor(pp *PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.PostProcessor, hcl.Diagnostics) {
// ProvisionerBlock represents a detected but unparsed provisioner
var diags hcl.Diagnostics
@ -64,7 +64,7 @@ func (p *Parser) startPostProcessor(pp *PostProcessorBlock, ectx *hcl.EvalContex
}
flatProvisinerCfg, moreDiags := decodeHCL2Spec(pp.Rest, ectx, postProcessor)
diags = append(diags, moreDiags...)
err = postProcessor.Configure(flatProvisinerCfg)
err = postProcessor.Configure(flatProvisinerCfg, generatedVars)
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,

View File

@ -5,7 +5,6 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/packer"
)
@ -47,7 +46,7 @@ func (p *Parser) decodeProvisioner(block *hcl.Block) (*ProvisionerBlock, hcl.Dia
return provisioner, diags
}
func (p *Parser) startProvisioner(pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars []string) (packer.Provisioner, hcl.Diagnostics) {
func (p *Parser) startProvisioner(pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.Provisioner, hcl.Diagnostics) {
var diags hcl.Diagnostics
provisioner, err := p.ProvisionersSchemas.Start(pb.PType)
@ -67,22 +66,10 @@ func (p *Parser) startProvisioner(pb *ProvisionerBlock, ectx *hcl.EvalContext, g
// manipulate generatedVars from builder to add to the interfaces being
// passed to the provisioner Prepare()
// If the builder has provided a list of to-be-generated variables that
// should be made accessible to provisioners, pass that list into
// the provisioner prepare() so that the provisioner can appropriately
// validate user input against what will become available. Otherwise,
// only pass the default variables, using the basic placeholder data.
generatedPlaceholderMap := packer.BasicPlaceholderData()
if generatedVars != nil {
for _, k := range generatedVars {
generatedPlaceholderMap[k] = fmt.Sprintf("Generated_%s. "+
common.PlaceholderMsg, k)
}
}
// configs := make([]interface{}, 2)
// configs = append(, flatProvisionerCfg)
// configs = append(configs, generatedPlaceholderMap)
err = provisioner.Prepare(flatProvisionerCfg, generatedPlaceholderMap)
// configs = append(configs, generatedVars)
err = provisioner.Prepare(flatProvisionerCfg, generatedVars)
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,

View File

@ -1,7 +1,9 @@
package hcl2template
import (
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/packer"
"github.com/zclconf/go-cty/cty"
)
@ -42,7 +44,7 @@ func (cfg *PackerConfig) EvalContext() *hcl.EvalContext {
// getCoreBuildProvisioners takes a list of provisioner block, starts according
// provisioners and sends parsed HCL2 over to it.
func (p *Parser) getCoreBuildProvisioners(blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars []string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) {
func (p *Parser) getCoreBuildProvisioners(blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) {
var diags hcl.Diagnostics
res := []packer.CoreBuildProvisioner{}
for _, pb := range blocks {
@ -62,11 +64,11 @@ func (p *Parser) getCoreBuildProvisioners(blocks []*ProvisionerBlock, ectx *hcl.
// getCoreBuildProvisioners takes a list of post processor block, starts
// according provisioners and sends parsed HCL2 over to it.
func (p *Parser) getCoreBuildPostProcessors(blocks []*PostProcessorBlock, ectx *hcl.EvalContext) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) {
func (p *Parser) getCoreBuildPostProcessors(blocks []*PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) {
var diags hcl.Diagnostics
res := []packer.CoreBuildPostProcessor{}
for _, ppb := range blocks {
postProcessor, moreDiags := p.startPostProcessor(ppb, ectx)
postProcessor, moreDiags := p.startPostProcessor(ppb, ectx, generatedVars)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
@ -104,12 +106,26 @@ func (p *Parser) getBuilds(cfg *PackerConfig) ([]packer.Build, hcl.Diagnostics)
if moreDiags.HasErrors() {
continue
}
provisioners, moreDiags := p.getCoreBuildProvisioners(build.ProvisionerBlocks, cfg.EvalContext(), generatedVars)
// If the builder has provided a list of to-be-generated variables that
// should be made accessible to provisioners, pass that list into
// the provisioner prepare() so that the provisioner can appropriately
// validate user input against what will become available. Otherwise,
// only pass the default variables, using the basic placeholder data.
generatedPlaceholderMap := packer.BasicPlaceholderData()
if generatedVars != nil {
for _, k := range generatedVars {
generatedPlaceholderMap[k] = fmt.Sprintf("Build_%s. "+
common.PlaceholderMsg, k)
}
}
provisioners, moreDiags := p.getCoreBuildProvisioners(build.ProvisionerBlocks, cfg.EvalContext(), generatedPlaceholderMap)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
}
postProcessors, moreDiags := p.getCoreBuildPostProcessors(build.PostProcessors, cfg.EvalContext())
postProcessors, moreDiags := p.getCoreBuildPostProcessors(build.PostProcessors, cfg.EvalContext(), generatedPlaceholderMap)
pps := [][]packer.CoreBuildPostProcessor{}
if len(postProcessors) > 0 {
pps = [][]packer.CoreBuildPostProcessor{postProcessors}
@ -124,6 +140,7 @@ func (p *Parser) getBuilds(cfg *PackerConfig) ([]packer.Build, hcl.Diagnostics)
Builder: builder,
Provisioners: provisioners,
PostProcessors: pps,
Prepared: true,
}
res = append(res, pcb)
}

View File

@ -57,8 +57,9 @@ func TestParser_complete(t *testing.T) {
false, false,
[]packer.Build{
&packer.CoreBuild{
Type: "virtualbox-iso",
Builder: basicMockBuilder,
Type: "virtualbox-iso",
Prepared: true,
Builder: basicMockBuilder,
Provisioners: []packer.CoreBuildProvisioner{
{
PType: "shell",

View File

@ -97,6 +97,9 @@ type CoreBuild struct {
TemplatePath string
Variables map[string]string
// Indicates whether the build is already initialized before calling Prepare(..)
Prepared bool
debug bool
force bool
onError string
@ -132,6 +135,13 @@ func (b *CoreBuild) Name() string {
// and any hooks. This _must_ be called prior to Run. The parameter is the
// overrides for the variables within the template (if any).
func (b *CoreBuild) Prepare() (warn []string, err error) {
// For HCL2 templates, the builder and hooks are initialized when the template is parsed.
// Calling Prepare(...) is not necessary
if b.Prepared {
b.prepareCalled = true
return
}
b.l.Lock()
defer b.l.Unlock()

View File

@ -88,6 +88,17 @@ func TestBuild_Prepare(t *testing.T) {
}
}
func TestBuild_Prepare_SkipWhenBuilderAlreadyInitialized(t *testing.T) {
build := testBuild()
builder := build.Builder.(*MockBuilder)
build.Prepared = true
build.Prepare()
if builder.PrepareCalled {
t.Fatal("should not be called")
}
}
func TestBuild_Prepare_Twice(t *testing.T) {
build := testBuild()
warn, err := build.Prepare()