diff --git a/command/meta.go b/command/meta.go index e55aebf42..1c0864f92 100644 --- a/command/meta.go +++ b/command/meta.go @@ -28,6 +28,7 @@ type Meta struct { CoreConfig *packer.CoreConfig Cache packer.Cache Ui packer.Ui + Version string // These are set by command-line flags flagBuildExcept []string @@ -42,6 +43,7 @@ func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) { config := *m.CoreConfig config.Template = tpl config.Variables = m.flagVars + config.Version = m.Version // Init the core core, err := packer.NewCore(&config) diff --git a/main.go b/main.go index 7f5cb7bef..4d23339d1 100644 --- a/main.go +++ b/main.go @@ -168,6 +168,7 @@ func wrappedMain() int { PostProcessor: config.LoadPostProcessor, Provisioner: config.LoadProvisioner, }, + Version: Version, }, Cache: cache, Ui: ui, diff --git a/packer/core.go b/packer/core.go index 3bc5d295e..f9bf87b9d 100644 --- a/packer/core.go +++ b/packer/core.go @@ -5,6 +5,7 @@ import ( "sort" "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-version" "github.com/mitchellh/packer/template" "github.com/mitchellh/packer/template/interpolate" ) @@ -17,6 +18,7 @@ type Core struct { components ComponentFinder variables map[string]string builds map[string]*template.Builder + version string } // CoreConfig is the structure for initializing a new Core. Once a CoreConfig @@ -25,6 +27,7 @@ type CoreConfig struct { Components ComponentFinder Template *template.Template Variables map[string]string + Version string } // The function type used to lookup Builder implementations. @@ -55,6 +58,7 @@ func NewCore(c *CoreConfig) (*Core, error) { Template: c.Template, components: c.Components, variables: c.Variables, + version: c.Version, } if err := result.validate(); err != nil { return nil, err @@ -226,6 +230,29 @@ func (c *Core) validate() error { return err } + // Validate the minimum version is satisfied + if c.Template.MinVersion != "" { + versionActual, err := version.NewVersion(c.version) + if err != nil { + // This shouldn't happen since we set it via the compiler + panic(err) + } + + versionMin, err := version.NewVersion(c.Template.MinVersion) + if err != nil { + return fmt.Errorf( + "min_version is invalid: %s", err) + } + + if versionActual.LessThan(versionMin) { + return fmt.Errorf( + "This template requires a minimum Packer version of %s,\n"+ + "but version %s is running.", + versionMin, + versionActual) + } + } + // Validate variables are set var err error for n, v := range c.Template.Variables { diff --git a/packer/core_test.go b/packer/core_test.go index cc958356e..07acea43c 100644 --- a/packer/core_test.go +++ b/packer/core_test.go @@ -484,6 +484,19 @@ func TestCoreValidate(t *testing.T) { map[string]string{"foo": "bar"}, false, }, + + // Min version good + { + "validate-min-version.json", + map[string]string{"foo": "bar"}, + false, + }, + + { + "validate-min-version-high.json", + map[string]string{"foo": "bar"}, + true, + }, } for _, tc := range cases { @@ -501,6 +514,7 @@ func TestCoreValidate(t *testing.T) { _, err = NewCore(&CoreConfig{ Template: tpl, Variables: tc.Vars, + Version: "1.0.0", }) if (err != nil) != tc.Err { t.Fatalf("err: %s\n\n%s", tc.File, err) diff --git a/packer/test-fixtures/validate-min-version-high.json b/packer/test-fixtures/validate-min-version-high.json new file mode 100644 index 000000000..2dd93a825 --- /dev/null +++ b/packer/test-fixtures/validate-min-version-high.json @@ -0,0 +1,7 @@ +{ + "min_packer_version": "2.1.0", + + "builders": [ + {"type": "foo"} + ] +} diff --git a/packer/test-fixtures/validate-min-version.json b/packer/test-fixtures/validate-min-version.json new file mode 100644 index 000000000..a8bd74214 --- /dev/null +++ b/packer/test-fixtures/validate-min-version.json @@ -0,0 +1,7 @@ +{ + "min_packer_version": "0.1.0", + + "builders": [ + {"type": "foo"} + ] +}