Skip to content

Commit 23fa310

Browse files
authored
Render variables one time on prepare method (#8727)
1 parent c2ad948 commit 23fa310

7 files changed

Lines changed: 76 additions & 3 deletions

File tree

builder/null/artifact_export.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ func (a *NullArtifact) String() string {
2525
}
2626

2727
func (a *NullArtifact) State(name string) interface{} {
28+
if name == "generated_data" {
29+
return map[interface{}]interface{}{
30+
"ID": "Null",
31+
}
32+
}
2833
return nil
2934
}
3035

builder/null/builder.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
4747
state := new(multistep.BasicStateBag)
4848
state.Put("hook", hook)
4949
state.Put("ui", ui)
50+
state.Put("instance_id", "Null")
5051

5152
// Run!
5253
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)

command/build_test.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,33 @@ func TestBuildOnlyFileMultipleFlags(t *testing.T) {
111111
}
112112
}
113113

114+
func TestBuildProvisionAndPosProcessWithBuildVariablesSharing(t *testing.T) {
115+
c := &BuildCommand{
116+
Meta: testMetaFile(t),
117+
}
118+
119+
args := []string{
120+
filepath.Join(testFixture("build-variable-sharing"), "template.json"),
121+
}
122+
123+
files := []string{
124+
"provisioner.Null.txt",
125+
"post-processor.Null.txt",
126+
}
127+
128+
defer cleanup(files...)
129+
130+
if code := c.Run(args); code != 0 {
131+
fatalCommand(t, c.Meta)
132+
}
133+
134+
for _, f := range files {
135+
if !fileExists(f) {
136+
t.Errorf("Expected to find %s", f)
137+
}
138+
}
139+
}
140+
114141
func TestBuildEverything(t *testing.T) {
115142
c := &BuildCommand{
116143
Meta: testMetaFile(t),
@@ -231,7 +258,7 @@ func testMetaFile(t *testing.T) Meta {
231258
}
232259
}
233260

234-
func cleanup() {
261+
func cleanup(moreFiles ...string) {
235262
os.RemoveAll("chocolate.txt")
236263
os.RemoveAll("vanilla.txt")
237264
os.RemoveAll("cherry.txt")
@@ -245,6 +272,9 @@ func cleanup() {
245272
os.RemoveAll("lilas.txt")
246273
os.RemoveAll("campanules.txt")
247274
os.RemoveAll("ducky.txt")
275+
for _, file := range moreFiles {
276+
os.RemoveAll(file)
277+
}
248278
}
249279

250280
func TestBuildCommand_ParseArgs(t *testing.T) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"builders": [
3+
{
4+
"name": "chocolate",
5+
"type": "null",
6+
"communicator": "none"
7+
}
8+
],
9+
"provisioners": [
10+
{
11+
"type": "shell-local",
12+
"inline": [
13+
"echo hi > provisioner.{{ build `ID`}}.txt"
14+
]
15+
}
16+
],
17+
"post-processors": [
18+
{
19+
"type": "shell-local",
20+
"inline": [
21+
"echo hi > post-processor.{{ build `ID`}}.txt"
22+
]
23+
}
24+
]
25+
}

packer/provisioner.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ func BasicPlaceholderData() map[string]string {
8080
}
8181

8282
func CastDataToMap(data interface{}) map[string]interface{} {
83+
84+
if interMap, ok := data.(map[string]interface{}); ok {
85+
// null and file builder sometimes don't use a communicator and
86+
// therefore don't go through RPC
87+
return interMap
88+
}
89+
8390
// Provisioners expect a map[string]interface{} in their data field, but
8491
// it gets converted into a map[interface]interface on the way over the
8592
// RPC. Check that data can be cast into such a form, and cast it.

template/interpolate/i.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ func NewContext() *Context {
4444
return &Context{}
4545
}
4646

47-
// Render is shorthand for constructing an I and calling Render.
47+
// RenderOnce is shorthand for constructing an I and calling Render one time.
48+
func RenderOnce(v string, ctx *Context) (string, error) {
49+
return (&I{Value: v}).Render(ctx)
50+
}
51+
52+
// Render is shorthand for constructing an I and calling Render until all variables are rendered.
4853
func Render(v string, ctx *Context) (rendered string, err error) {
4954
// Keep interpolating until all variables are done
5055
// Sometimes a variable can been inside another one

template/interpolate/render.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func RenderMap(v interface{}, ctx *Context, f *RenderFilter) (map[string]interfa
5757
// RenderInterface renders any value and returns the resulting value.
5858
func RenderInterface(v interface{}, ctx *Context) (interface{}, error) {
5959
f := func(v string) (string, error) {
60-
return Render(v, ctx)
60+
return RenderOnce(v, ctx)
6161
}
6262

6363
walker := &renderWalker{

0 commit comments

Comments
 (0)