diff --git a/CHANGELOG.md b/CHANGELOG.md index 8531d8d5b..8c0037526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,8 @@ BUG FIXES: * core: User variables can now be used for non-string fields. [GH-598] * core: Fix bad download paths if the download URL contained a "." before a "/" [GH-716] +* core: "{{timestamp}}" values will always be the same for the entire + duration of a build. [GH-744] * builder/virtualbox: don't download guest additions if disabled. [GH-731] * post-processor/vsphere: Uploads VM properly. [GH-694] * post-processor/vsphere: Process user variables. diff --git a/packer/config_template.go b/packer/config_template.go index 98dde878d..3df291005 100644 --- a/packer/config_template.go +++ b/packer/config_template.go @@ -9,6 +9,15 @@ import ( "time" ) +// InitTime is the UTC time when this package was initialized. It is +// used as the timestamp for all configuration templates so that they +// match for a single build. +var InitTime time.Time + +func init() { + InitTime = time.Now().UTC() +} + // ConfigTemplate processes string data as a text/template with some common // elements and functions available. Plugin creators should process as // many fields as possible through this. @@ -89,7 +98,7 @@ func templateISOTime() string { } func templateTimestamp() string { - return strconv.FormatInt(time.Now().UTC().Unix(), 10) + return strconv.FormatInt(InitTime.Unix(), 10) } func templateUuid() string { diff --git a/packer/config_template_test.go b/packer/config_template_test.go index dad1b0dc8..dd1e01da8 100644 --- a/packer/config_template_test.go +++ b/packer/config_template_test.go @@ -49,6 +49,17 @@ func TestConfigTemplateProcess_timestamp(t *testing.T) { if math.Abs(float64(currentTime-val)) > 10 { t.Fatalf("val: %d (current: %d)", val, currentTime) } + + time.Sleep(2 * time.Second) + + result2, err := tpl.Process(`{{timestamp}}`, nil) + if err != nil { + t.Fatalf("err: %s", err) + } + + if result != result2 { + t.Fatalf("bad: %#v %#v", result, result2) + } } func TestConfigTemplateProcess_user(t *testing.T) {