From 62c3743890667c05f26231276829d7b9f07a6805 Mon Sep 17 00:00:00 2001 From: sylviamoss Date: Thu, 13 Aug 2020 19:16:13 +0200 Subject: [PATCH 1/2] implemet override provisioner's option for hcl2 --- hcl2template/types.build.provisioners.go | 38 +++++++++++++++---- hcl2template/types.hcl_provisioner.go | 4 +- .../partials/provisioners/common-config.mdx | 20 +++++++++- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/hcl2template/types.build.provisioners.go b/hcl2template/types.build.provisioners.go index 0d9d07607..a50156782 100644 --- a/hcl2template/types.build.provisioners.go +++ b/hcl2template/types.build.provisioners.go @@ -6,7 +6,9 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" + hcl2shim "github.com/hashicorp/packer/hcl2template/shim" "github.com/hashicorp/packer/packer" + "github.com/zclconf/go-cty/cty" ) // OnlyExcept is a struct that is meant to be embedded that contains the @@ -62,6 +64,7 @@ type ProvisionerBlock struct { PauseBefore time.Duration MaxRetries int Timeout time.Duration + Override map[string]interface{} OnlyExcept OnlyExcept HCL2Ref } @@ -72,13 +75,14 @@ func (p *ProvisionerBlock) String() string { func (p *Parser) decodeProvisioner(block *hcl.Block, cfg *PackerConfig) (*ProvisionerBlock, hcl.Diagnostics) { var b struct { - Name string `hcl:"name,optional"` - PauseBefore string `hcl:"pause_before,optional"` - MaxRetries int `hcl:"max_retries,optional"` - Timeout string `hcl:"timeout,optional"` - Only []string `hcl:"only,optional"` - Except []string `hcl:"except,optional"` - Rest hcl.Body `hcl:",remain"` + Name string `hcl:"name,optional"` + PauseBefore string `hcl:"pause_before,optional"` + MaxRetries int `hcl:"max_retries,optional"` + Timeout string `hcl:"timeout,optional"` + Only []string `hcl:"only,optional"` + Except []string `hcl:"except,optional"` + Override cty.Value `hcl:"override,optional"` + Rest hcl.Body `hcl:",remain"` } diags := gohcl.DecodeBody(block.Body, cfg.EvalContext(nil), &b) if diags.HasErrors() { @@ -98,6 +102,18 @@ func (p *Parser) decodeProvisioner(block *hcl.Block, cfg *PackerConfig) (*Provis return nil, diags } + if !b.Override.IsNull() { + override := make(map[string]interface{}) + for buildName, overrides := range b.Override.AsValueMap() { + buildOverrides := make(map[string]interface{}) + for option, value := range overrides.AsValueMap() { + buildOverrides[option] = hcl2shim.ConfigValueFromHCL2(value) + } + override[buildName] = buildOverrides + } + provisioner.Override = override + } + if b.PauseBefore != "" { pauseBefore, err := time.ParseDuration(b.PauseBefore) if err != nil { @@ -144,12 +160,20 @@ func (cfg *PackerConfig) startProvisioner(source SourceBlock, pb *ProvisionerBlo }) return nil, diags } + hclProvisioner := &HCL2Provisioner{ Provisioner: provisioner, provisionerBlock: pb, evalContext: ectx, builderVariables: source.builderVariables(), } + + if pb.Override != nil { + if override, ok := pb.Override[source.name()]; ok { + hclProvisioner.override = override.(map[string]interface{}) + } + } + err = hclProvisioner.HCL2Prepare(nil) if err != nil { diags = append(diags, &hcl.Diagnostic{ diff --git a/hcl2template/types.hcl_provisioner.go b/hcl2template/types.hcl_provisioner.go index 6411f9167..03b925763 100644 --- a/hcl2template/types.hcl_provisioner.go +++ b/hcl2template/types.hcl_provisioner.go @@ -3,7 +3,6 @@ package hcl2template import ( "context" "fmt" - "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/packer/packer" @@ -19,6 +18,7 @@ type HCL2Provisioner struct { provisionerBlock *ProvisionerBlock evalContext *hcl.EvalContext builderVariables map[string]string + override map[string]interface{} } func (p *HCL2Provisioner) ConfigSpec() hcldec.ObjectSpec { @@ -55,7 +55,7 @@ func (p *HCL2Provisioner) HCL2Prepare(buildVars map[string]interface{}) error { if diags.HasErrors() { return diags } - return p.Provisioner.Prepare(p.builderVariables, flatProvisionerCfg) + return p.Provisioner.Prepare(p.builderVariables, flatProvisionerCfg, p.override) } func (p *HCL2Provisioner) Prepare(args ...interface{}) error { diff --git a/website/pages/partials/provisioners/common-config.mdx b/website/pages/partials/provisioners/common-config.mdx index d819686fc..1fe77e06f 100644 --- a/website/pages/partials/provisioners/common-config.mdx +++ b/website/pages/partials/provisioners/common-config.mdx @@ -10,17 +10,33 @@ Parameters common to all provisioners: - `override` (object) - Override the builder with different settings for a specific builder, eg : + In JSON: ```json { "type": "shell", "script": "script.sh", "override": { - "vmware-iso": { - "execute_command": "echo 'password' | sudo -S bash {{.Path}}" + "example_one": { + "script": "basic_one-script.sh" } } } ``` + In HCL2: + ```hcl + build { + sources = ["docker.example_one", "docker.example_two"] + provisioner "shell" { + script = "script.sh" + override = { + example_one = { + script = "basic-one-script.sh" + } + } + } + } + ``` + - `timeout` (duration) - If the provisioner takes more than for example `1h10m1s` or `10m` to finish, the provisioner will timeout and fail. From 39a8dee4ea78fa2d47c1123bbe9fa3d3e05ca40b Mon Sep 17 00:00:00 2001 From: sylviamoss Date: Fri, 14 Aug 2020 11:22:51 +0200 Subject: [PATCH 2/2] add tests and update override example --- command/build_test.go | 48 ++++++++++++----- .../hcl/provisioner-override.pkr.hcl | 19 +++++++ .../provisioners/provisioner-override.json | 25 +++++++++ .../partials/provisioners/common-config.mdx | 54 +++++++++++++------ 4 files changed, 117 insertions(+), 29 deletions(-) create mode 100644 command/test-fixtures/hcl/provisioner-override.pkr.hcl create mode 100644 command/test-fixtures/provisioners/provisioner-override.json diff --git a/command/build_test.go b/command/build_test.go index 735f243d4..71be284a7 100644 --- a/command/build_test.go +++ b/command/build_test.go @@ -328,19 +328,32 @@ func TestBuild(t *testing.T) { func Test_build_output(t *testing.T) { tc := []struct { - command []string - env []string - expected string - runtime string + command []string + env []string + expected []string + notExpected []string + runtime string }{ - {[]string{"build", "--color=false", testFixture("hcl", "reprepare", "shell-local.pkr.hcl")}, nil, - ` - null.example: hello from the NULL builder packeruser -Build 'null.example' finished after`, "posix"}, - {[]string{"build", "--color=false", testFixture("hcl", "reprepare", "shell-local-windows.pkr.hcl")}, nil, - ` - null.example: hello from the NULL builder packeruser -Build 'null.example' finished after`, "windows"}, + {[]string{"build", "--color=false", testFixture("hcl", "reprepare", "shell-local.pkr.hcl")}, + nil, + []string{"null.example: hello from the NULL builder packeruser", "Build 'null.example' finished after"}, + []string{}, + "posix"}, + {[]string{"build", "--color=false", testFixture("hcl", "reprepare", "shell-local-windows.pkr.hcl")}, + nil, + []string{"null.example: hello from the NULL builder packeruser", "Build 'null.example' finished after"}, + []string{}, + "windows"}, + {[]string{"build", "--color=false", testFixture("hcl", "provisioner-override.pkr.hcl")}, + nil, + []string{"null.example1: yes overridden", "null.example2: not overridden"}, + []string{"null.example2: yes overridden", "null.example1: not overridden"}, + "posix"}, + {[]string{"build", "--color=false", testFixture("provisioners", "provisioner-override.json")}, + nil, + []string{"example1: yes overridden", "example2: not overridden"}, + []string{"example2: yes overridden", "example1: not overridden"}, + "posix"}, } for _, tc := range tc { @@ -354,8 +367,15 @@ Build 'null.example' finished after`, "windows"}, if err != nil { t.Fatalf("%v: %s", err, bs) } - if !strings.Contains(string(bs), tc.expected) { - t.Fatalf("Should contain output %s.\nReceived: %s", tc.expected, string(bs)) + for _, expected := range tc.expected { + if !strings.Contains(string(bs), expected) { + t.Fatalf("Should contain output %s.\nReceived: %s", tc.expected, string(bs)) + } + } + for _, notExpected := range tc.notExpected { + if strings.Contains(string(bs), notExpected) { + t.Fatalf("Should NOT contain output %s.\nReceived: %s", tc.expected, string(bs)) + } } }) } diff --git a/command/test-fixtures/hcl/provisioner-override.pkr.hcl b/command/test-fixtures/hcl/provisioner-override.pkr.hcl new file mode 100644 index 000000000..a52c84dc3 --- /dev/null +++ b/command/test-fixtures/hcl/provisioner-override.pkr.hcl @@ -0,0 +1,19 @@ +source "null" "example1" { + communicator = "none" +} + +source "null" "example2" { + communicator = "none" +} + +build { + sources = ["source.null.example1", "source.null.example2"] + provisioner "shell-local" { + inline = ["echo not overridden"] + override = { + example1 = { + inline = ["echo yes overridden"] + } + } + } +} \ No newline at end of file diff --git a/command/test-fixtures/provisioners/provisioner-override.json b/command/test-fixtures/provisioners/provisioner-override.json new file mode 100644 index 000000000..53d2c8236 --- /dev/null +++ b/command/test-fixtures/provisioners/provisioner-override.json @@ -0,0 +1,25 @@ +{ + "builders": [ + { + "type": "null", + "name": "example1", + "communicator": "none" + }, + { + "type": "null", + "name": "example2", + "communicator": "none" + } + ], + "provisioners": [ + { + "type": "shell-local", + "inline": ["echo not overridden"], + "override": { + "example1": { + "inline": ["echo yes overridden"] + } + } + } + ] +} \ No newline at end of file diff --git a/website/pages/partials/provisioners/common-config.mdx b/website/pages/partials/provisioners/common-config.mdx index 1fe77e06f..d5e282d7a 100644 --- a/website/pages/partials/provisioners/common-config.mdx +++ b/website/pages/partials/provisioners/common-config.mdx @@ -13,29 +13,53 @@ Parameters common to all provisioners: In JSON: ```json { - "type": "shell", - "script": "script.sh", - "override": { - "example_one": { - "script": "basic_one-script.sh" + "builders": [ + { + "type": "null", + "name": "example1", + "communicator": "none" + }, + { + "type": "null", + "name": "example2", + "communicator": "none" } - } + ], + "provisioners": [ + { + "type": "shell-local", + "inline": ["echo not overridden"], + "override": { + "example1": { + "inline": ["echo yes overridden"] + } + } + } + ] } ``` In HCL2: ```hcl - build { - sources = ["docker.example_one", "docker.example_two"] - provisioner "shell" { - script = "script.sh" - override = { - example_one = { - script = "basic-one-script.sh" - } - } + source "null" "example1" { + communicator = "none" + } + + source "null" "example2" { + communicator = "none" + } + + build { + sources = ["source.null.example1", "source.null.example2"] + provisioner "shell-local" { + inline = ["echo not overridden"] + override = { + example1 = { + inline = ["echo yes overridden"] } + } } + } ``` - `timeout` (duration) - If the provisioner takes more than for example