From 2d1a67c6cb0e5ef8728238fd3d730293d87650ef Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 16 Jan 2020 12:08:39 +0100 Subject: [PATCH] hcl2: allow to optionnaly name provisioners and post-processors --- hcl2template/decode.go | 4 +- hcl2template/testdata/complete/build.pkr.hcl | 41 +++++++++++++++++++ hcl2template/types.build.go | 2 +- hcl2template/types.build.post-processor.go | 42 ++++++++++++++------ hcl2template/types.build.provisioners.go | 39 ++++++++++++------ hcl2template/types.hcl_ref.go | 15 ++++++- hcl2template/types.packer_config.go | 10 +++-- hcl2template/types.packer_config_test.go | 29 ++++++++++++-- hcl2template/types.source.go | 2 +- packer/build.go | 1 + 10 files changed, 146 insertions(+), 39 deletions(-) diff --git a/hcl2template/decode.go b/hcl2template/decode.go index e7be2136e..18046d9ff 100644 --- a/hcl2template/decode.go +++ b/hcl2template/decode.go @@ -10,6 +10,6 @@ type Decodable interface { ConfigSpec() hcldec.ObjectSpec } -func decodeHCL2Spec(block *hcl.Block, ctx *hcl.EvalContext, dec Decodable) (cty.Value, hcl.Diagnostics) { - return hcldec.Decode(block.Body, dec.ConfigSpec(), ctx) +func decodeHCL2Spec(body hcl.Body, ctx *hcl.EvalContext, dec Decodable) (cty.Value, hcl.Diagnostics) { + return hcldec.Decode(body, dec.ConfigSpec(), ctx) } diff --git a/hcl2template/testdata/complete/build.pkr.hcl b/hcl2template/testdata/complete/build.pkr.hcl index de67e1c39..bd84d42fd 100644 --- a/hcl2template/testdata/complete/build.pkr.hcl +++ b/hcl2template/testdata/complete/build.pkr.hcl @@ -6,6 +6,7 @@ build { ] provisioner "shell" { + name = "provisioner that does something" string = "string" int = 42 int64 = 43 @@ -83,6 +84,46 @@ build { } } + post-processor "amazon-import" { + name = "something" + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + + nested { + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + } + + nested_slice { + } + } + post-processor "amazon-import" { string = "string" int = 42 diff --git a/hcl2template/types.build.go b/hcl2template/types.build.go index 6f3485b95..f40342683 100644 --- a/hcl2template/types.build.go +++ b/hcl2template/types.build.go @@ -78,7 +78,7 @@ func (p *Parser) decodeBuildConfig(block *hcl.Block) (*BuildBlock, hcl.Diagnosti } build.ProvisionerBlocks = append(build.ProvisionerBlocks, p) case buildPostProcessorLabel: - pp, moreDiags := p.decodePostProcessorGroup(block) + pp, moreDiags := p.decodePostProcessor(block) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue diff --git a/hcl2template/types.build.post-processor.go b/hcl2template/types.build.post-processor.go index 7575b17c7..125bcfcb2 100644 --- a/hcl2template/types.build.post-processor.go +++ b/hcl2template/types.build.post-processor.go @@ -4,27 +4,43 @@ import ( "fmt" "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/packer/packer" ) // PostProcessorBlock represents a parsed PostProcessorBlock type PostProcessorBlock struct { PType string - block *hcl.Block + PName string + + HCL2Ref } -func (p *Parser) decodePostProcessorGroup(block *hcl.Block) (*PostProcessorBlock, hcl.Diagnostics) { - postProcessor := &PostProcessorBlock{ - PType: block.Labels[0], - block: block, +func (p *PostProcessorBlock) String() string { + return fmt.Sprintf(buildPostProcessorLabel+"-block %q %q", p.PType, p.PName) +} + +func (p *Parser) decodePostProcessor(block *hcl.Block) (*PostProcessorBlock, hcl.Diagnostics) { + var b struct { + Name string `hcl:"name,optional"` + Rest hcl.Body `hcl:",remain"` + } + diags := gohcl.DecodeBody(block.Body, nil, &b) + if diags.HasErrors() { + return nil, diags + } + + postProcessor := &PostProcessorBlock{ + PType: block.Labels[0], + PName: b.Name, + HCL2Ref: newHCL2Ref(block, b.Rest), } - var diags hcl.Diagnostics if !p.PostProcessorsSchemas.Has(postProcessor.PType) { diags = append(diags, &hcl.Diagnostic{ - Summary: "Unknown " + buildPostProcessorLabel + " type " + postProcessor.PType, + Summary: fmt.Sprintf("Unknown "+buildPostProcessorLabel+" type %q", postProcessor.PType), Subject: block.LabelRanges[0].Ptr(), - Detail: fmt.Sprintf("known provisioners: %v", p.ProvisionersSchemas.List()), + Detail: fmt.Sprintf("known "+buildPostProcessorLabel+"s: %v", p.PostProcessorsSchemas.List()), Severity: hcl.DiagError, }) return nil, diags @@ -39,21 +55,21 @@ func (p *Parser) StartPostProcessor(pp *PostProcessorBlock) (packer.PostProcesso postProcessor, err := p.PostProcessorsSchemas.Start(pp.PType) if err != nil { diags = append(diags, &hcl.Diagnostic{ - Summary: "Failed loading " + pp.block.Type, - Subject: pp.block.LabelRanges[0].Ptr(), + Summary: fmt.Sprintf("Failed loading %s", pp.PType), + Subject: pp.DefRange.Ptr(), Detail: err.Error(), }) return nil, diags } - flatProvisinerCfg, moreDiags := decodeHCL2Spec(pp.block, nil, postProcessor) + flatProvisinerCfg, moreDiags := decodeHCL2Spec(pp.Rest, nil, postProcessor) diags = append(diags, moreDiags...) err = postProcessor.Configure(flatProvisinerCfg) if err != nil { diags = append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, - Summary: "Failed preparing " + pp.block.Type, + Summary: fmt.Sprintf("Failed preparing %s", pp), Detail: err.Error(), - Subject: pp.block.DefRange.Ptr(), + Subject: pp.DefRange.Ptr(), }) return nil, diags } diff --git a/hcl2template/types.build.provisioners.go b/hcl2template/types.build.provisioners.go index 7fd832a6c..0af33a747 100644 --- a/hcl2template/types.build.provisioners.go +++ b/hcl2template/types.build.provisioners.go @@ -2,7 +2,9 @@ package hcl2template import ( "fmt" + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/packer/helper/common" "github.com/hashicorp/packer/packer" ) @@ -10,21 +12,34 @@ import ( // ProvisionerBlock represents a parsed provisioner type ProvisionerBlock struct { PType string - block *hcl.Block + PName string + HCL2Ref +} + +func (p *ProvisionerBlock) String() string { + return fmt.Sprintf(buildProvisionerLabel+"-block %q %q", p.PType, p.PName) } func (p *Parser) decodeProvisioner(block *hcl.Block) (*ProvisionerBlock, hcl.Diagnostics) { - provisioner := &ProvisionerBlock{ - PType: block.Labels[0], - block: block, + var b struct { + Name string `hcl:"name,optional"` + Rest hcl.Body `hcl:",remain"` + } + diags := gohcl.DecodeBody(block.Body, nil, &b) + if diags.HasErrors() { + return nil, diags + } + provisioner := &ProvisionerBlock{ + PType: block.Labels[0], + PName: b.Name, + HCL2Ref: newHCL2Ref(block, b.Rest), } - var diags hcl.Diagnostics if !p.ProvisionersSchemas.Has(provisioner.PType) { diags = append(diags, &hcl.Diagnostic{ - Summary: "Unknown " + buildProvisionerLabel + " type " + provisioner.PType, + Summary: fmt.Sprintf("Unknown "+buildProvisionerLabel+" type %q", provisioner.PType), Subject: block.LabelRanges[0].Ptr(), - Detail: fmt.Sprintf("known provisioners: %v", p.ProvisionersSchemas.List()), + Detail: fmt.Sprintf("known "+buildProvisionerLabel+"s: %v", p.ProvisionersSchemas.List()), Severity: hcl.DiagError, }) return nil, diags @@ -38,13 +53,13 @@ func (p *Parser) StartProvisioner(pb *ProvisionerBlock, generatedVars []string) provisioner, err := p.ProvisionersSchemas.Start(pb.PType) if err != nil { diags = append(diags, &hcl.Diagnostic{ - Summary: "Failed loading " + pb.block.Type, - Subject: pb.block.LabelRanges[0].Ptr(), + Summary: fmt.Sprintf("failed loading %s", pb.PType), + Subject: pb.HCL2Ref.LabelsRanges[0].Ptr(), Detail: err.Error(), }) return nil, diags } - flatProvisionerCfg, moreDiags := decodeHCL2Spec(pb.block, nil, provisioner) + flatProvisionerCfg, moreDiags := decodeHCL2Spec(pb.HCL2Ref.Rest, nil, provisioner) diags = append(diags, moreDiags...) if diags.HasErrors() { return nil, diags @@ -71,9 +86,9 @@ func (p *Parser) StartProvisioner(pb *ProvisionerBlock, generatedVars []string) if err != nil { diags = append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, - Summary: "Failed preparing " + pb.block.Type, + Summary: fmt.Sprintf("Failed preparing %s", pb), Detail: err.Error(), - Subject: pb.block.DefRange.Ptr(), + Subject: pb.HCL2Ref.DefRange.Ptr(), }) return nil, diags } diff --git a/hcl2template/types.hcl_ref.go b/hcl2template/types.hcl_ref.go index 3c8060298..e6e58e314 100644 --- a/hcl2template/types.hcl_ref.go +++ b/hcl2template/types.hcl_ref.go @@ -7,8 +7,19 @@ import ( // reference to the source definition in configuration text file type HCL2Ref struct { // reference to the source definition in configuration text file - DeclRange hcl.Range + DefRange hcl.Range + TypeRange hcl.Range + LabelsRanges []hcl.Range // remainder of unparsed body - Remain hcl.Body + Rest hcl.Body +} + +func newHCL2Ref(block *hcl.Block, rest hcl.Body) HCL2Ref { + return HCL2Ref{ + Rest: rest, + DefRange: block.DefRange, + TypeRange: block.TypeRange, + LabelsRanges: block.LabelRanges, + } } diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index f3f061aa2..e2a4806b6 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -25,6 +25,7 @@ func (p *Parser) CoreBuildProvisioners(blocks []*ProvisionerBlock, generatedVars } res = append(res, packer.CoreBuildProvisioner{ PType: pb.PType, + PName: pb.PName, Provisioner: provisioner, }) } @@ -34,15 +35,16 @@ func (p *Parser) CoreBuildProvisioners(blocks []*ProvisionerBlock, generatedVars func (p *Parser) CoreBuildPostProcessors(blocks []*PostProcessorBlock) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) { var diags hcl.Diagnostics res := []packer.CoreBuildPostProcessor{} - for _, pp := range blocks { - postProcessor, moreDiags := p.StartPostProcessor(pp) + for _, ppb := range blocks { + postProcessor, moreDiags := p.StartPostProcessor(ppb) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue } res = append(res, packer.CoreBuildPostProcessor{ PostProcessor: postProcessor, - PType: pp.PType, + PName: ppb.PName, + PType: ppb.PType, }) } @@ -59,7 +61,7 @@ func (p *Parser) getBuilds(cfg *PackerConfig) ([]packer.Build, hcl.Diagnostics) if !found { diags = append(diags, &hcl.Diagnostic{ Summary: "Unknown " + sourceLabel + " " + from.String(), - Subject: build.HCL2Ref.DeclRange.Ptr(), + Subject: build.HCL2Ref.DefRange.Ptr(), Severity: hcl.DiagError, }) continue diff --git a/hcl2template/types.packer_config_test.go b/hcl2template/types.packer_config_test.go index 0e410a850..325f31722 100644 --- a/hcl2template/types.packer_config_test.go +++ b/hcl2template/types.packer_config_test.go @@ -26,11 +26,20 @@ func TestParser_complete(t *testing.T) { &BuildBlock{ Froms: []SourceRef{refVBIsoUbuntu1204}, ProvisionerBlocks: []*ProvisionerBlock{ - {PType: "shell"}, + { + PType: "shell", + PName: "provisioner that does something", + }, {PType: "file"}, }, PostProcessors: []*PostProcessorBlock{ - {PType: "amazon-import"}, + { + PType: "amazon-import", + PName: "something", + }, + { + PType: "amazon-import", + }, }, }, }, @@ -41,12 +50,24 @@ func TestParser_complete(t *testing.T) { Type: "virtualbox-iso", Builder: basicMockBuilder, Provisioners: []packer.CoreBuildProvisioner{ - {PType: "shell", Provisioner: basicMockProvisioner}, + { + PType: "shell", + PName: "provisioner that does something", + Provisioner: basicMockProvisioner, + }, {PType: "file", Provisioner: basicMockProvisioner}, }, PostProcessors: [][]packer.CoreBuildPostProcessor{ { - {PType: "amazon-import", PostProcessor: basicMockPostProcessor}, + { + PType: "amazon-import", + PName: "something", + PostProcessor: basicMockPostProcessor, + }, + { + PType: "amazon-import", + PostProcessor: basicMockPostProcessor, + }, }, }, }, diff --git a/hcl2template/types.source.go b/hcl2template/types.source.go index 47eddfa70..45678d1c5 100644 --- a/hcl2template/types.source.go +++ b/hcl2template/types.source.go @@ -52,7 +52,7 @@ func (p *Parser) StartBuilder(source *Source) (packer.Builder, hcl.Diagnostics, return builder, diags, nil } - decoded, moreDiags := decodeHCL2Spec(source.block, nil, builder) + decoded, moreDiags := decodeHCL2Spec(source.block.Body, nil, builder) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { return nil, diags, nil diff --git a/packer/build.go b/packer/build.go index f1b8a11c3..808d69d77 100644 --- a/packer/build.go +++ b/packer/build.go @@ -118,6 +118,7 @@ type CoreBuildPostProcessor struct { // the provisioner within the build. type CoreBuildProvisioner struct { PType string + PName string Provisioner Provisioner config []interface{} }