packer: min_packer_version [GH-487]
This commit is contained in:
parent
9ef50487fb
commit
edcb8fea30
|
@ -8,6 +8,8 @@ FEATURES:
|
||||||
command, which talks to a Chef Server. [GH-855]
|
command, which talks to a Chef Server. [GH-855]
|
||||||
* **New provisioner:** `puppet-server` - Provision using Puppet by
|
* **New provisioner:** `puppet-server` - Provision using Puppet by
|
||||||
communicating to a Puppet master. [GH-796]
|
communicating to a Puppet master. [GH-796]
|
||||||
|
* `min_packer_version` can be specified in a Packer template to force
|
||||||
|
a minimum version. [GH-487]
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package packer
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/hashicorp/go-version"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
jsonutil "github.com/mitchellh/packer/common/json"
|
jsonutil "github.com/mitchellh/packer/common/json"
|
||||||
"io"
|
"io"
|
||||||
|
@ -18,12 +19,14 @@ import (
|
||||||
// "interface{}" pointers since we actually don't know what their contents
|
// "interface{}" pointers since we actually don't know what their contents
|
||||||
// are until we read the "type" field.
|
// are until we read the "type" field.
|
||||||
type rawTemplate struct {
|
type rawTemplate struct {
|
||||||
|
MinimumPackerVersion string `mapstructure:"min_packer_version"`
|
||||||
|
|
||||||
Description string
|
Description string
|
||||||
Variables map[string]interface{}
|
|
||||||
Builders []map[string]interface{}
|
Builders []map[string]interface{}
|
||||||
Hooks map[string][]string
|
Hooks map[string][]string
|
||||||
Provisioners []map[string]interface{}
|
|
||||||
PostProcessors []interface{} `mapstructure:"post-processors"`
|
PostProcessors []interface{} `mapstructure:"post-processors"`
|
||||||
|
Provisioners []map[string]interface{}
|
||||||
|
Variables map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Template struct represents a parsed template, parsed into the most
|
// The Template struct represents a parsed template, parsed into the most
|
||||||
|
@ -115,6 +118,25 @@ func ParseTemplate(data []byte, vars map[string]string) (t *Template, err error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rawTpl.MinimumPackerVersion != "" {
|
||||||
|
vCur, err := version.NewVersion(Version)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
vReq, err := version.NewVersion(rawTpl.MinimumPackerVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"'minimum_packer_version' error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if vCur.LessThan(vReq) {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"Template requires Packer version %s. " +
|
||||||
|
"Running version is %s.",
|
||||||
|
vReq, vCur)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errors := make([]error, 0)
|
errors := make([]error, 0)
|
||||||
|
|
||||||
if len(md.Unused) > 0 {
|
if len(md.Unused) > 0 {
|
||||||
|
|
|
@ -60,6 +60,69 @@ func TestParseTemplateFile_basic(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseTemplateFile_minPackerVersionBad(t *testing.T) {
|
||||||
|
data := `
|
||||||
|
{
|
||||||
|
"min_packer_version": "27.0.0",
|
||||||
|
"builders": [{"type": "something"}]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
tf, err := ioutil.TempFile("", "packer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
tf.Write([]byte(data))
|
||||||
|
tf.Close()
|
||||||
|
|
||||||
|
_, err = ParseTemplateFile(tf.Name(), nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expects error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseTemplateFile_minPackerVersionFormat(t *testing.T) {
|
||||||
|
data := `
|
||||||
|
{
|
||||||
|
"min_packer_version": "NOPE NOPE NOPE",
|
||||||
|
"builders": [{"type": "something"}]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
tf, err := ioutil.TempFile("", "packer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
tf.Write([]byte(data))
|
||||||
|
tf.Close()
|
||||||
|
|
||||||
|
_, err = ParseTemplateFile(tf.Name(), nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expects error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseTemplateFile_minPackerVersionGood(t *testing.T) {
|
||||||
|
data := `
|
||||||
|
{
|
||||||
|
"min_packer_version": "0.1",
|
||||||
|
"builders": [{"type": "something"}]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
tf, err := ioutil.TempFile("", "packer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
tf.Write([]byte(data))
|
||||||
|
tf.Close()
|
||||||
|
|
||||||
|
_, err = ParseTemplateFile(tf.Name(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseTemplateFile_stdin(t *testing.T) {
|
func TestParseTemplateFile_stdin(t *testing.T) {
|
||||||
data := `
|
data := `
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,6 +43,12 @@ Along with each key, it is noted whether it is required or not.
|
||||||
information on what post-processors do and how they're defined, read the
|
information on what post-processors do and how they're defined, read the
|
||||||
sub-section on [configuring post-processors in templates](/docs/templates/post-processors.html).
|
sub-section on [configuring post-processors in templates](/docs/templates/post-processors.html).
|
||||||
|
|
||||||
|
* `min_packer_version` (optional) is a string that has a minimum Packer
|
||||||
|
version that is required to parse the template. This can be used to
|
||||||
|
ensure that proper versions of Packer are used with the template. A
|
||||||
|
max version can't be specified because Packer retains backwards
|
||||||
|
compatibility with `packer fix`.
|
||||||
|
|
||||||
## Example Template
|
## Example Template
|
||||||
|
|
||||||
Below is an example of a basic template that is nearly fully functional. It is just
|
Below is an example of a basic template that is nearly fully functional. It is just
|
||||||
|
|
Loading…
Reference in New Issue