2015-05-19 17:25:56 -04:00
|
|
|
package template
|
|
|
|
|
|
|
|
import (
|
2015-05-21 17:29:45 -04:00
|
|
|
"errors"
|
2015-05-19 17:25:56 -04:00
|
|
|
"fmt"
|
|
|
|
"time"
|
2015-05-21 17:29:45 -04:00
|
|
|
|
|
|
|
"github.com/hashicorp/go-multierror"
|
2015-05-19 17:25:56 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// Template represents the parsed template that is used to configure
|
|
|
|
// Packer builds.
|
|
|
|
type Template struct {
|
2015-05-29 17:05:13 -04:00
|
|
|
// Path is the path to the template. This will be blank if Parse is
|
|
|
|
// used, but will be automatically populated by ParseFile.
|
|
|
|
Path string
|
|
|
|
|
2015-05-19 17:25:56 -04:00
|
|
|
Description string
|
|
|
|
MinVersion string
|
|
|
|
|
|
|
|
Variables map[string]*Variable
|
|
|
|
Builders map[string]*Builder
|
|
|
|
Provisioners []*Provisioner
|
|
|
|
PostProcessors [][]*PostProcessor
|
2015-05-28 18:18:36 -04:00
|
|
|
Push Push
|
2015-05-26 12:38:02 -04:00
|
|
|
|
|
|
|
// RawContents is just the raw data for this template
|
|
|
|
RawContents []byte
|
2015-05-19 17:25:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Builder represents a builder configured in the template
|
|
|
|
type Builder struct {
|
|
|
|
Name string
|
|
|
|
Type string
|
|
|
|
Config map[string]interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PostProcessor represents a post-processor within the template.
|
|
|
|
type PostProcessor struct {
|
2015-05-21 16:32:22 -04:00
|
|
|
OnlyExcept `mapstructure:",squash"`
|
2015-05-19 17:25:56 -04:00
|
|
|
|
|
|
|
Type string
|
2015-05-21 16:32:22 -04:00
|
|
|
KeepInputArtifact bool `mapstructure:"keep_input_artifact"`
|
2015-05-19 17:25:56 -04:00
|
|
|
Config map[string]interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Provisioner represents a provisioner within the template.
|
|
|
|
type Provisioner struct {
|
2015-05-21 15:34:44 -04:00
|
|
|
OnlyExcept `mapstructure:",squash"`
|
2015-05-19 17:25:56 -04:00
|
|
|
|
|
|
|
Type string
|
|
|
|
Config map[string]interface{}
|
|
|
|
Override map[string]interface{}
|
2015-05-21 15:34:44 -04:00
|
|
|
PauseBefore time.Duration `mapstructure:"pause_before"`
|
2015-05-19 17:25:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Push represents the configuration for pushing the template to Atlas.
|
|
|
|
type Push struct {
|
|
|
|
Name string
|
|
|
|
Address string
|
|
|
|
BaseDir string `mapstructure:"base_dir"`
|
|
|
|
Include []string
|
|
|
|
Exclude []string
|
|
|
|
Token string
|
|
|
|
VCS bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// Variable represents a variable within the template
|
|
|
|
type Variable struct {
|
|
|
|
Default string
|
|
|
|
Required bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// OnlyExcept is a struct that is meant to be embedded that contains the
|
|
|
|
// logic required for "only" and "except" meta-parameters.
|
|
|
|
type OnlyExcept struct {
|
|
|
|
Only []string
|
|
|
|
Except []string
|
|
|
|
}
|
|
|
|
|
2015-05-21 17:29:45 -04:00
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Functions
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Validate does some basic validation of the template on top of the
|
|
|
|
// validation that occurs while parsing. If possible, we try to defer
|
|
|
|
// validation to here. The validation errors that occur during parsing
|
|
|
|
// are the minimal necessary to make sure parsing builds a reasonable
|
|
|
|
// Template structure.
|
|
|
|
func (t *Template) Validate() error {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// At least one builder must be defined
|
|
|
|
if len(t.Builders) == 0 {
|
|
|
|
err = multierror.Append(err, errors.New(
|
|
|
|
"at least one builder must be defined"))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the provisioner overrides target builders that exist
|
|
|
|
for i, p := range t.Provisioners {
|
2015-05-21 17:39:32 -04:00
|
|
|
// Validate only/except
|
|
|
|
if verr := p.OnlyExcept.Validate(t); verr != nil {
|
|
|
|
for _, e := range multierror.Append(verr).Errors {
|
|
|
|
err = multierror.Append(err, fmt.Errorf(
|
|
|
|
"provisioner %d: %s", i+1, e))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate overrides
|
2016-11-01 17:08:04 -04:00
|
|
|
for name := range p.Override {
|
2015-05-21 17:29:45 -04:00
|
|
|
if _, ok := t.Builders[name]; !ok {
|
|
|
|
err = multierror.Append(err, fmt.Errorf(
|
|
|
|
"provisioner %d: override '%s' doesn't exist",
|
|
|
|
i+1, name))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-21 17:42:12 -04:00
|
|
|
// Verify post-processors
|
|
|
|
for i, chain := range t.PostProcessors {
|
|
|
|
for j, p := range chain {
|
|
|
|
// Validate only/except
|
|
|
|
if verr := p.OnlyExcept.Validate(t); verr != nil {
|
|
|
|
for _, e := range multierror.Append(verr).Errors {
|
|
|
|
err = multierror.Append(err, fmt.Errorf(
|
|
|
|
"post-processor %d.%d: %s", i+1, j+1, e))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-21 17:29:45 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-05-26 12:07:16 -04:00
|
|
|
// Skip says whether or not to skip the build with the given name.
|
|
|
|
func (o *OnlyExcept) Skip(n string) bool {
|
|
|
|
if len(o.Only) > 0 {
|
|
|
|
for _, v := range o.Only {
|
|
|
|
if v == n {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(o.Except) > 0 {
|
|
|
|
for _, v := range o.Except {
|
|
|
|
if v == n {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2015-05-21 17:39:32 -04:00
|
|
|
// Validate validates that the OnlyExcept settings are correct for a thing.
|
|
|
|
func (o *OnlyExcept) Validate(t *Template) error {
|
|
|
|
if len(o.Only) > 0 && len(o.Except) > 0 {
|
|
|
|
return errors.New("only one of 'only' or 'except' may be specified")
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
for _, n := range o.Only {
|
|
|
|
if _, ok := t.Builders[n]; !ok {
|
|
|
|
err = multierror.Append(err, fmt.Errorf(
|
|
|
|
"'only' specified builder '%s' not found", n))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, n := range o.Except {
|
|
|
|
if _, ok := t.Builders[n]; !ok {
|
|
|
|
err = multierror.Append(err, fmt.Errorf(
|
|
|
|
"'except' specified builder '%s' not found", n))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-05-19 17:25:56 -04:00
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// GoStringer
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
|
|
func (b *Builder) GoString() string {
|
|
|
|
return fmt.Sprintf("*%#v", *b)
|
|
|
|
}
|
2015-05-21 15:34:44 -04:00
|
|
|
|
|
|
|
func (p *Provisioner) GoString() string {
|
|
|
|
return fmt.Sprintf("*%#v", *p)
|
|
|
|
}
|
2015-05-21 16:32:22 -04:00
|
|
|
|
|
|
|
func (p *PostProcessor) GoString() string {
|
|
|
|
return fmt.Sprintf("*%#v", *p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Variable) GoString() string {
|
|
|
|
return fmt.Sprintf("*%#v", *v)
|
|
|
|
}
|