HCL2: pass on builder type and name (#8956)
* sets `packer_build_name` and `packer_builder_type` variables for builder provisioners and post-processors in HCL2 * allows to use the new `${source.type}` and `${source.name}` variables in HCL2 * fixes #8932 Note that the common.PackerConfig is used everywhere and was not set for HCL2, this had some implications: For #8923 you can see the issue here:dde74232f2/builder/lxd/config.go (L61-L63)
More random examples of where this could cause an issue :0785c2f6fc/provisioner/ansible-local/provisioner.go (L380-L381)
b4efd13a4d/builder/amazon/ebs/builder.go (L232-L236)
* [All references to PackerConfig.PackerBuildName](https://sourcegraph.com/github.com/hashicorp/packer@ff6a039d5bb45e34ff761d9c52e8b98972288447/-/blob/common/packer_config.go#L7:2&tab=references) * [All references to PackerConfig.PackerBuilderType](https://sourcegraph.com/github.com/hashicorp/packer@ff6a039d5bb45e34ff761d9c52e8b98972288447/-/blob/common/packer_config.go#L8:2&tab=references)
This commit is contained in:
parent
c358682411
commit
2af40c762b
|
@ -3,6 +3,7 @@ package command
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -12,12 +13,14 @@ import (
|
||||||
"github.com/hashicorp/packer/builder/file"
|
"github.com/hashicorp/packer/builder/file"
|
||||||
"github.com/hashicorp/packer/builder/null"
|
"github.com/hashicorp/packer/builder/null"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
|
"github.com/hashicorp/packer/post-processor/manifest"
|
||||||
shell_local_pp "github.com/hashicorp/packer/post-processor/shell-local"
|
shell_local_pp "github.com/hashicorp/packer/post-processor/shell-local"
|
||||||
|
filep "github.com/hashicorp/packer/provisioner/file"
|
||||||
"github.com/hashicorp/packer/provisioner/shell"
|
"github.com/hashicorp/packer/provisioner/shell"
|
||||||
shell_local "github.com/hashicorp/packer/provisioner/shell-local"
|
shell_local "github.com/hashicorp/packer/provisioner/shell-local"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBuild_VarArgs(t *testing.T) {
|
func TestBuild(t *testing.T) {
|
||||||
tc := []struct {
|
tc := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
|
@ -25,7 +28,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
fileCheck
|
fileCheck
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "json - json varfile sets an apple env var",
|
name: "var-args: json - json varfile sets an apple env var",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.json"),
|
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.json"),
|
||||||
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
|
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
|
||||||
|
@ -43,7 +46,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
fileCheck: fileCheck{expected: []string{"banana.txt"}},
|
fileCheck: fileCheck{expected: []string{"banana.txt"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "json - arg sets a pear env var",
|
name: "var-args: json - arg sets a pear env var",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var=fruit=pear",
|
"-var=fruit=pear",
|
||||||
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
|
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
|
||||||
|
@ -52,7 +55,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "json - inexistent var file errs",
|
name: "var-args: json - inexistent var file errs",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.json"),
|
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.json"),
|
||||||
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
|
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
|
||||||
|
@ -62,7 +65,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hcl - inexistent json var file errs",
|
name: "var-args: hcl - inexistent json var file errs",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.json"),
|
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.json"),
|
||||||
testFixture("var-arg"),
|
testFixture("var-arg"),
|
||||||
|
@ -72,7 +75,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hcl - inexistent hcl var file errs",
|
name: "var-args: hcl - inexistent hcl var file errs",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.hcl"),
|
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.hcl"),
|
||||||
testFixture("var-arg"),
|
testFixture("var-arg"),
|
||||||
|
@ -82,7 +85,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hcl - auto varfile sets a chocolate env var",
|
name: "var-args: hcl - auto varfile sets a chocolate env var",
|
||||||
args: []string{
|
args: []string{
|
||||||
testFixture("var-arg"),
|
testFixture("var-arg"),
|
||||||
},
|
},
|
||||||
|
@ -90,7 +93,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hcl - hcl varfile sets a apple env var",
|
name: "var-args: hcl - hcl varfile sets a apple env var",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.hcl"),
|
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.hcl"),
|
||||||
testFixture("var-arg"),
|
testFixture("var-arg"),
|
||||||
|
@ -99,7 +102,7 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hcl - json varfile sets a apple env var",
|
name: "var-args: hcl - json varfile sets a apple env var",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.json"),
|
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.json"),
|
||||||
testFixture("var-arg"),
|
testFixture("var-arg"),
|
||||||
|
@ -108,19 +111,108 @@ func TestBuild_VarArgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hcl - arg sets a tomato env var",
|
name: "var-args: hcl - arg sets a tomato env var",
|
||||||
args: []string{
|
args: []string{
|
||||||
"-var=fruit=tomato",
|
"-var=fruit=tomato",
|
||||||
testFixture("var-arg"),
|
testFixture("var-arg"),
|
||||||
},
|
},
|
||||||
fileCheck: fileCheck{expected: []string{"tomato.txt"}},
|
fileCheck: fileCheck{expected: []string{"tomato.txt"}},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "build name: HCL",
|
||||||
|
args: []string{
|
||||||
|
"-parallel-builds=1", // to ensure order is kept
|
||||||
|
testFixture("build-name-and-type"),
|
||||||
|
},
|
||||||
|
fileCheck: fileCheck{
|
||||||
|
expectedContent: map[string]string{
|
||||||
|
"manifest.json": `{
|
||||||
|
"builds": [
|
||||||
|
{
|
||||||
|
"name": "test",
|
||||||
|
"builder_type": "null",
|
||||||
|
"files": null,
|
||||||
|
"artifact_id": "Null",
|
||||||
|
"packer_run_uuid": "",
|
||||||
|
"custom_data": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "potato",
|
||||||
|
"builder_type": "null",
|
||||||
|
"files": null,
|
||||||
|
"artifact_id": "Null",
|
||||||
|
"packer_run_uuid": "",
|
||||||
|
"custom_data": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_run_uuid": ""
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "build name: JSON except potato",
|
||||||
|
args: []string{
|
||||||
|
"-except=potato",
|
||||||
|
"-parallel-builds=1", // to ensure order is kept
|
||||||
|
filepath.Join(testFixture("build-name-and-type"), "all.json"),
|
||||||
|
},
|
||||||
|
fileCheck: fileCheck{
|
||||||
|
expected: []string{
|
||||||
|
"null.test.txt",
|
||||||
|
"null.potato.txt",
|
||||||
|
},
|
||||||
|
expectedContent: map[string]string{
|
||||||
|
"manifest.json": `{
|
||||||
|
"builds": [
|
||||||
|
{
|
||||||
|
"name": "test",
|
||||||
|
"builder_type": "null",
|
||||||
|
"files": null,
|
||||||
|
"artifact_id": "Null",
|
||||||
|
"packer_run_uuid": "",
|
||||||
|
"custom_data": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_run_uuid": ""
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "build name: JSON only potato",
|
||||||
|
args: []string{
|
||||||
|
"-only=potato",
|
||||||
|
"-parallel-builds=1", // to ensure order is kept
|
||||||
|
filepath.Join(testFixture("build-name-and-type"), "all.json"),
|
||||||
|
},
|
||||||
|
fileCheck: fileCheck{
|
||||||
|
expectedContent: map[string]string{
|
||||||
|
"manifest.json": `{
|
||||||
|
"builds": [
|
||||||
|
{
|
||||||
|
"name": "potato",
|
||||||
|
"builder_type": "null",
|
||||||
|
"files": null,
|
||||||
|
"artifact_id": "Null",
|
||||||
|
"packer_run_uuid": "",
|
||||||
|
"custom_data": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_run_uuid": ""
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tc {
|
for _, tt := range tc {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
defer tt.cleanup(t)
|
||||||
run(t, tt.args, tt.expectedCode)
|
run(t, tt.args, tt.expectedCode)
|
||||||
defer cleanup()
|
|
||||||
tt.fileCheck.verify(t)
|
tt.fileCheck.verify(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -340,10 +432,28 @@ func run(t *testing.T, args []string, expectedCode int) {
|
||||||
|
|
||||||
type fileCheck struct {
|
type fileCheck struct {
|
||||||
expected, notExpected []string
|
expected, notExpected []string
|
||||||
|
expectedContent map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc fileCheck) cleanup(t *testing.T) {
|
||||||
|
for _, file := range fc.expectedFiles() {
|
||||||
|
t.Logf("removing %v", file)
|
||||||
|
if err := os.Remove(file); err != nil {
|
||||||
|
t.Errorf("failed to remove file %s: %v", file, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc fileCheck) expectedFiles() []string {
|
||||||
|
expected := fc.expected
|
||||||
|
for file := range fc.expectedContent {
|
||||||
|
expected = append(expected, file)
|
||||||
|
}
|
||||||
|
return expected
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fc fileCheck) verify(t *testing.T) {
|
func (fc fileCheck) verify(t *testing.T) {
|
||||||
for _, f := range fc.expected {
|
for _, f := range fc.expectedFiles() {
|
||||||
if !fileExists(f) {
|
if !fileExists(f) {
|
||||||
t.Errorf("Expected to find %s", f)
|
t.Errorf("Expected to find %s", f)
|
||||||
}
|
}
|
||||||
|
@ -353,6 +463,15 @@ func (fc fileCheck) verify(t *testing.T) {
|
||||||
t.Errorf("Expected to not find %s", f)
|
t.Errorf("Expected to not find %s", f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for file, expectedContent := range fc.expectedContent {
|
||||||
|
content, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ioutil.ReadFile: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(expectedContent, string(content)); diff != "" {
|
||||||
|
t.Errorf("content of %s differs: %s", file, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileExists returns true if the filename is found
|
// fileExists returns true if the filename is found
|
||||||
|
@ -374,9 +493,11 @@ func testCoreConfigBuilder(t *testing.T) *packer.CoreConfig {
|
||||||
ProvisionerStore: packer.MapOfProvisioner{
|
ProvisionerStore: packer.MapOfProvisioner{
|
||||||
"shell-local": func() (packer.Provisioner, error) { return &shell_local.Provisioner{}, nil },
|
"shell-local": func() (packer.Provisioner, error) { return &shell_local.Provisioner{}, nil },
|
||||||
"shell": func() (packer.Provisioner, error) { return &shell.Provisioner{}, nil },
|
"shell": func() (packer.Provisioner, error) { return &shell.Provisioner{}, nil },
|
||||||
|
"file": func() (packer.Provisioner, error) { return &filep.Provisioner{}, nil },
|
||||||
},
|
},
|
||||||
PostProcessorStore: packer.MapOfPostProcessor{
|
PostProcessorStore: packer.MapOfPostProcessor{
|
||||||
"shell-local": func() (packer.PostProcessor, error) { return &shell_local_pp.PostProcessor{}, nil },
|
"shell-local": func() (packer.PostProcessor, error) { return &shell_local_pp.PostProcessor{}, nil },
|
||||||
|
"manifest": func() (packer.PostProcessor, error) { return &manifest.PostProcessor{}, nil },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return &packer.CoreConfig{
|
return &packer.CoreConfig{
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"builders": [
|
||||||
|
{
|
||||||
|
"name": "test",
|
||||||
|
"communicator": "none",
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "potato",
|
||||||
|
"communicator": "none",
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"post-processors": [
|
||||||
|
{
|
||||||
|
"type": "manifest",
|
||||||
|
"output": "manifest.json",
|
||||||
|
"strip_time": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
source "null" "test" {
|
||||||
|
communicator = "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
source "null" "potato" {
|
||||||
|
communicator = "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
build {
|
||||||
|
sources = [
|
||||||
|
"sources.null.test",
|
||||||
|
"sources.null.potato",
|
||||||
|
]
|
||||||
|
|
||||||
|
provisioner "shell-local" {
|
||||||
|
inline = [
|
||||||
|
"echo '' > ${source.type}.${source.name}.txt"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post-processor "manifest" {
|
||||||
|
output = "manifest.json"
|
||||||
|
strip_time = true
|
||||||
|
}
|
||||||
|
}
|
|
@ -166,7 +166,7 @@ func (p *Parser) parse(filename string, varFiles []string, argVars map[string]st
|
||||||
func (p *Parser) decodeConfig(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics {
|
func (p *Parser) decodeConfig(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics {
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
|
|
||||||
body := dynblock.Expand(f.Body, cfg.EvalContext())
|
body := dynblock.Expand(f.Body, cfg.EvalContext(nil))
|
||||||
content, moreDiags := body.Content(configSchema)
|
content, moreDiags := body.Content(configSchema)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ func (p *Parser) decodePostProcessor(block *hcl.Block) (*PostProcessorBlock, hcl
|
||||||
return postProcessor, diags
|
return postProcessor, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) startPostProcessor(pp *PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.PostProcessor, hcl.Diagnostics) {
|
func (p *Parser) startPostProcessor(source *SourceBlock, pp *PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.PostProcessor, hcl.Diagnostics) {
|
||||||
// ProvisionerBlock represents a detected but unparsed provisioner
|
// ProvisionerBlock represents a detected but unparsed provisioner
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ func (p *Parser) startPostProcessor(pp *PostProcessorBlock, ectx *hcl.EvalContex
|
||||||
}
|
}
|
||||||
flatProvisinerCfg, moreDiags := decodeHCL2Spec(pp.Rest, ectx, postProcessor)
|
flatProvisinerCfg, moreDiags := decodeHCL2Spec(pp.Rest, ectx, postProcessor)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
err = postProcessor.Configure(flatProvisinerCfg, generatedVars)
|
err = postProcessor.Configure(source.builderVariables(), flatProvisinerCfg, generatedVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
|
|
|
@ -46,7 +46,7 @@ func (p *Parser) decodeProvisioner(block *hcl.Block) (*ProvisionerBlock, hcl.Dia
|
||||||
return provisioner, diags
|
return provisioner, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) startProvisioner(pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.Provisioner, hcl.Diagnostics) {
|
func (p *Parser) startProvisioner(source *SourceBlock, pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.Provisioner, hcl.Diagnostics) {
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
|
|
||||||
provisioner, err := p.ProvisionersSchemas.Start(pb.PType)
|
provisioner, err := p.ProvisionersSchemas.Start(pb.PType)
|
||||||
|
@ -69,7 +69,7 @@ func (p *Parser) startProvisioner(pb *ProvisionerBlock, ectx *hcl.EvalContext, g
|
||||||
// configs := make([]interface{}, 2)
|
// configs := make([]interface{}, 2)
|
||||||
// configs = append(, flatProvisionerCfg)
|
// configs = append(, flatProvisionerCfg)
|
||||||
// configs = append(configs, generatedVars)
|
// configs = append(configs, generatedVars)
|
||||||
err = provisioner.Prepare(flatProvisionerCfg, generatedVars)
|
err = provisioner.Prepare(source.builderVariables(), flatProvisionerCfg, generatedVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
|
|
|
@ -35,19 +35,32 @@ type ValidationOptions struct {
|
||||||
Strict bool
|
Strict bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
inputVariablesAccessor = "var"
|
||||||
|
localsAccessor = "local"
|
||||||
|
sourcesAccessor = "source"
|
||||||
|
)
|
||||||
|
|
||||||
// EvalContext returns the *hcl.EvalContext that will be passed to an hcl
|
// EvalContext returns the *hcl.EvalContext that will be passed to an hcl
|
||||||
// decoder in order to tell what is the actual value of a var or a local and
|
// decoder in order to tell what is the actual value of a var or a local and
|
||||||
// the list of defined functions.
|
// the list of defined functions.
|
||||||
func (cfg *PackerConfig) EvalContext() *hcl.EvalContext {
|
func (cfg *PackerConfig) EvalContext(variables map[string]cty.Value) *hcl.EvalContext {
|
||||||
inputVariables, _ := cfg.InputVariables.Values()
|
inputVariables, _ := cfg.InputVariables.Values()
|
||||||
localVariables, _ := cfg.LocalVariables.Values()
|
localVariables, _ := cfg.LocalVariables.Values()
|
||||||
ectx := &hcl.EvalContext{
|
ectx := &hcl.EvalContext{
|
||||||
Functions: Functions(cfg.Basedir),
|
Functions: Functions(cfg.Basedir),
|
||||||
Variables: map[string]cty.Value{
|
Variables: map[string]cty.Value{
|
||||||
"var": cty.ObjectVal(inputVariables),
|
inputVariablesAccessor: cty.ObjectVal(inputVariables),
|
||||||
"local": cty.ObjectVal(localVariables),
|
localsAccessor: cty.ObjectVal(localVariables),
|
||||||
|
sourcesAccessor: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"type": cty.UnknownVal(cty.String),
|
||||||
|
"name": cty.UnknownVal(cty.String),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
for k, v := range variables {
|
||||||
|
ectx.Variables[k] = v
|
||||||
|
}
|
||||||
return ectx
|
return ectx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +170,7 @@ func (c *PackerConfig) evaluateLocalVariables(locals []*Local) hcl.Diagnostics {
|
||||||
func (c *PackerConfig) evaluateLocalVariable(local *Local) hcl.Diagnostics {
|
func (c *PackerConfig) evaluateLocalVariable(local *Local) hcl.Diagnostics {
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
|
|
||||||
value, moreDiags := local.Expr.Value(c.EvalContext())
|
value, moreDiags := local.Expr.Value(c.EvalContext(nil))
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
if moreDiags.HasErrors() {
|
if moreDiags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
|
@ -173,11 +186,11 @@ func (c *PackerConfig) evaluateLocalVariable(local *Local) hcl.Diagnostics {
|
||||||
|
|
||||||
// getCoreBuildProvisioners takes a list of provisioner block, starts according
|
// getCoreBuildProvisioners takes a list of provisioner block, starts according
|
||||||
// provisioners and sends parsed HCL2 over to it.
|
// provisioners and sends parsed HCL2 over to it.
|
||||||
func (p *Parser) getCoreBuildProvisioners(blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) {
|
func (p *Parser) getCoreBuildProvisioners(source *SourceBlock, blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) {
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
res := []packer.CoreBuildProvisioner{}
|
res := []packer.CoreBuildProvisioner{}
|
||||||
for _, pb := range blocks {
|
for _, pb := range blocks {
|
||||||
provisioner, moreDiags := p.startProvisioner(pb, ectx, generatedVars)
|
provisioner, moreDiags := p.startProvisioner(source, pb, ectx, generatedVars)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
if moreDiags.HasErrors() {
|
if moreDiags.HasErrors() {
|
||||||
continue
|
continue
|
||||||
|
@ -193,11 +206,11 @@ func (p *Parser) getCoreBuildProvisioners(blocks []*ProvisionerBlock, ectx *hcl.
|
||||||
|
|
||||||
// getCoreBuildProvisioners takes a list of post processor block, starts
|
// getCoreBuildProvisioners takes a list of post processor block, starts
|
||||||
// according provisioners and sends parsed HCL2 over to it.
|
// according provisioners and sends parsed HCL2 over to it.
|
||||||
func (p *Parser) getCoreBuildPostProcessors(blocks []*PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) {
|
func (p *Parser) getCoreBuildPostProcessors(source *SourceBlock, blocks []*PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) {
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
res := []packer.CoreBuildPostProcessor{}
|
res := []packer.CoreBuildPostProcessor{}
|
||||||
for _, ppb := range blocks {
|
for _, ppb := range blocks {
|
||||||
postProcessor, moreDiags := p.startPostProcessor(ppb, ectx, generatedVars)
|
postProcessor, moreDiags := p.startPostProcessor(source, ppb, ectx, generatedVars)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
if moreDiags.HasErrors() {
|
if moreDiags.HasErrors() {
|
||||||
continue
|
continue
|
||||||
|
@ -230,12 +243,19 @@ func (p *Parser) getBuilds(cfg *PackerConfig) ([]packer.Build, hcl.Diagnostics)
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
builder, moreDiags, generatedVars := p.startBuilder(src, cfg.EvalContext())
|
builder, moreDiags, generatedVars := p.startBuilder(src, cfg.EvalContext(nil))
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
if moreDiags.HasErrors() {
|
if moreDiags.HasErrors() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variables := map[string]cty.Value{
|
||||||
|
sourcesAccessor: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"type": cty.StringVal(src.Type),
|
||||||
|
"name": cty.StringVal(src.Name),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
// If the builder has provided a list of to-be-generated variables that
|
// If the builder has provided a list of to-be-generated variables that
|
||||||
// should be made accessible to provisioners, pass that list into
|
// should be made accessible to provisioners, pass that list into
|
||||||
// the provisioner prepare() so that the provisioner can appropriately
|
// the provisioner prepare() so that the provisioner can appropriately
|
||||||
|
@ -249,12 +269,12 @@ func (p *Parser) getBuilds(cfg *PackerConfig) ([]packer.Build, hcl.Diagnostics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provisioners, moreDiags := p.getCoreBuildProvisioners(build.ProvisionerBlocks, cfg.EvalContext(), generatedPlaceholderMap)
|
provisioners, moreDiags := p.getCoreBuildProvisioners(src, build.ProvisionerBlocks, cfg.EvalContext(variables), generatedPlaceholderMap)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
if moreDiags.HasErrors() {
|
if moreDiags.HasErrors() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
postProcessors, moreDiags := p.getCoreBuildPostProcessors(build.PostProcessors, cfg.EvalContext(), generatedPlaceholderMap)
|
postProcessors, moreDiags := p.getCoreBuildPostProcessors(src, build.PostProcessors, cfg.EvalContext(variables), generatedPlaceholderMap)
|
||||||
pps := [][]packer.CoreBuildPostProcessor{}
|
pps := [][]packer.CoreBuildPostProcessor{}
|
||||||
if len(postProcessors) > 0 {
|
if len(postProcessors) > 0 {
|
||||||
pps = [][]packer.CoreBuildPostProcessor{postProcessors}
|
pps = [][]packer.CoreBuildPostProcessor{postProcessors}
|
||||||
|
|
|
@ -57,12 +57,19 @@ func (p *Parser) startBuilder(source *SourceBlock, ectx *hcl.EvalContext) (packe
|
||||||
return nil, diags, nil
|
return nil, diags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
generatedVars, warning, err := builder.Prepare(decoded)
|
generatedVars, warning, err := builder.Prepare(source.builderVariables(), decoded)
|
||||||
moreDiags = warningErrorsToDiags(source.block, warning, err)
|
moreDiags = warningErrorsToDiags(source.block, warning, err)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
return builder, diags, generatedVars
|
return builder, diags, generatedVars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (source *SourceBlock) builderVariables() map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"packer_build_name": source.Name,
|
||||||
|
"packer_builder_type": source.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (source *SourceBlock) Ref() SourceRef {
|
func (source *SourceBlock) Ref() SourceRef {
|
||||||
return SourceRef{
|
return SourceRef{
|
||||||
Type: source.Type,
|
Type: source.Type,
|
||||||
|
|
|
@ -12,7 +12,7 @@ type ArtifactFile struct {
|
||||||
type Artifact struct {
|
type Artifact struct {
|
||||||
BuildName string `json:"name"`
|
BuildName string `json:"name"`
|
||||||
BuilderType string `json:"builder_type"`
|
BuilderType string `json:"builder_type"`
|
||||||
BuildTime int64 `json:"build_time"`
|
BuildTime int64 `json:"build_time,omitempty"`
|
||||||
ArtifactFiles []ArtifactFile `json:"files"`
|
ArtifactFiles []ArtifactFile `json:"files"`
|
||||||
ArtifactId string `json:"artifact_id"`
|
ArtifactId string `json:"artifact_id"`
|
||||||
PackerRunUUID string `json:"packer_run_uuid"`
|
PackerRunUUID string `json:"packer_run_uuid"`
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//go:generate mapstructure-to-hcl2 -type Config
|
//go:generate mapstructure-to-hcl2 -type Config
|
||||||
|
//go:generate struct-markdown
|
||||||
|
|
||||||
package manifest
|
package manifest
|
||||||
|
|
||||||
|
@ -22,8 +23,17 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
common.PackerConfig `mapstructure:",squash"`
|
common.PackerConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
OutputPath string `mapstructure:"output"`
|
// The manifest will be written to this file. This defaults to
|
||||||
StripPath bool `mapstructure:"strip_path"`
|
// `packer-manifest.json`.
|
||||||
|
OutputPath string `mapstructure:"output"`
|
||||||
|
// Write only filename without the path to the manifest file. This defaults
|
||||||
|
// to false.
|
||||||
|
StripPath bool `mapstructure:"strip_path"`
|
||||||
|
// Don't write the `build_time` field from the output.
|
||||||
|
StripTime bool `mapstructure:"strip_time"`
|
||||||
|
// Arbitrary data to add to the manifest. This is a [template
|
||||||
|
// engine](https://packer.io/docs/templates/engine.html). Therefore, you
|
||||||
|
// may use user variables and template functions in this field.
|
||||||
CustomData map[string]string `mapstructure:"custom_data"`
|
CustomData map[string]string `mapstructure:"custom_data"`
|
||||||
ctx interpolate.Context
|
ctx interpolate.Context
|
||||||
}
|
}
|
||||||
|
@ -101,6 +111,9 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, source pa
|
||||||
artifact.BuilderType = p.config.PackerBuilderType
|
artifact.BuilderType = p.config.PackerBuilderType
|
||||||
artifact.BuildName = p.config.PackerBuildName
|
artifact.BuildName = p.config.PackerBuildName
|
||||||
artifact.BuildTime = time.Now().Unix()
|
artifact.BuildTime = time.Now().Unix()
|
||||||
|
if p.config.StripTime {
|
||||||
|
artifact.BuildTime = 0
|
||||||
|
}
|
||||||
// Since each post-processor runs in a different process we need a way to
|
// Since each post-processor runs in a different process we need a way to
|
||||||
// coordinate between various post-processors in a single packer run. We do
|
// coordinate between various post-processors in a single packer run. We do
|
||||||
// this by setting a UUID per run and tracking this in the manifest file.
|
// this by setting a UUID per run and tracking this in the manifest file.
|
||||||
|
|
|
@ -18,6 +18,7 @@ type FlatConfig struct {
|
||||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"`
|
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"`
|
||||||
OutputPath *string `mapstructure:"output" cty:"output"`
|
OutputPath *string `mapstructure:"output" cty:"output"`
|
||||||
StripPath *bool `mapstructure:"strip_path" cty:"strip_path"`
|
StripPath *bool `mapstructure:"strip_path" cty:"strip_path"`
|
||||||
|
StripTime *bool `mapstructure:"strip_time" cty:"strip_time"`
|
||||||
CustomData map[string]string `mapstructure:"custom_data" cty:"custom_data"`
|
CustomData map[string]string `mapstructure:"custom_data" cty:"custom_data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||||
"output": &hcldec.AttrSpec{Name: "output", Type: cty.String, Required: false},
|
"output": &hcldec.AttrSpec{Name: "output", Type: cty.String, Required: false},
|
||||||
"strip_path": &hcldec.AttrSpec{Name: "strip_path", Type: cty.Bool, Required: false},
|
"strip_path": &hcldec.AttrSpec{Name: "strip_path", Type: cty.Bool, Required: false},
|
||||||
|
"strip_time": &hcldec.AttrSpec{Name: "strip_time", Type: cty.Bool, Required: false},
|
||||||
"custom_data": &hcldec.BlockAttrsSpec{TypeName: "custom_data", ElementType: cty.String, Required: false},
|
"custom_data": &hcldec.BlockAttrsSpec{TypeName: "custom_data", ElementType: cty.String, Required: false},
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -36,19 +36,13 @@ post-processors such as Docker and Artifice.
|
||||||
|
|
||||||
### Optional:
|
### Optional:
|
||||||
|
|
||||||
- `output` (string) The manifest will be written to this file. This defaults
|
@include 'post-processor/manifest/Config-not-required.mdx'
|
||||||
to `packer-manifest.json`.
|
- `keep_input_artifact` (boolean) - Unlike most other post-processors, the
|
||||||
- `strip_path` (boolean) Write only filename without the path to the manifest
|
keep_input_artifact option will have no effect for the manifest
|
||||||
file. This defaults to false.
|
post-processor. We will always retain the input artifact for manifest,
|
||||||
- `custom_data` (map of strings) Arbitrary data to add to the manifest.
|
since deleting the files we just recorded is not a behavior anyone should
|
||||||
This is a [template engine](/docs/templates/engine). Therefore, you
|
ever expect. `keep_input_artifact will` therefore always be evaluated as
|
||||||
may use user variables and template functions in this field.
|
true, regardless of the value you enter into this field.
|
||||||
- `keep_input_artifact` (boolean) - Unlike most other post-processors, the
|
|
||||||
keep_input_artifact option will have no effect for the manifest
|
|
||||||
post-processor. We will always retain the input artifact for manifest,
|
|
||||||
since deleting the files we just recorded is not a behavior anyone should
|
|
||||||
ever expect. `keep_input_artifact will` therefore always be evaluated as
|
|
||||||
true, regardless of the value you enter into this field.
|
|
||||||
|
|
||||||
### Example Configuration
|
### Example Configuration
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!-- Code generated from the comments of the Config struct in post-processor/manifest/post-processor.go; DO NOT EDIT MANUALLY -->
|
||||||
|
|
||||||
|
- `output` (string) - The manifest will be written to this file. This defaults to
|
||||||
|
`packer-manifest.json`.
|
||||||
|
|
||||||
|
- `strip_path` (bool) - Write only filename without the path to the manifest file. This defaults
|
||||||
|
to false.
|
||||||
|
|
||||||
|
- `strip_time` (bool) - Don't write the `build_time` field from the output.
|
||||||
|
|
||||||
|
- `custom_data` (map[string]string) - Arbitrary data to add to the manifest. This is a [template
|
||||||
|
engine](https://packer.io/docs/templates/engine.html). Therefore, you
|
||||||
|
may use user variables and template functions in this field.
|
||||||
|
|
Loading…
Reference in New Issue