1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
package template
import (
"errors"
"fmt"
"time"
multierror "github.com/hashicorp/go-multierror"
)
// Template represents the parsed template that is used to configure
// Packer builds.
type Template struct {
// Path is the path to the template. This will be blank if Parse is
// used, but will be automatically populated by ParseFile.
Path string
Description string
MinVersion string
Variables map[string]*Variable
SensitiveVariables []*Variable
Builders map[string]*Builder
Provisioners []*Provisioner
PostProcessors [][]*PostProcessor
Push Push
// RawContents is just the raw data for this template
RawContents []byte
}
// 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 {
OnlyExcept `mapstructure:",squash"`
Name string
Type string
KeepInputArtifact bool `mapstructure:"keep_input_artifact"`
Config map[string]interface{}
}
// Provisioner represents a provisioner within the template.
type Provisioner struct {
OnlyExcept `mapstructure:",squash"`
Type string
Config map[string]interface{}
Override map[string]interface{}
PauseBefore time.Duration `mapstructure:"pause_before"`
}
// 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
}
//-------------------------------------------------------------------
// 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 {
// 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
for name := range p.Override {
if _, ok := t.Builders[name]; !ok {
err = multierror.Append(err, fmt.Errorf(
"provisioner %d: override '%s' doesn't exist",
i+1, name))
}
}
}
// 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))
}
}
}
}
return err
}
// 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
}
// 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
}
//-------------------------------------------------------------------
// GoStringer
//-------------------------------------------------------------------
func (b *Builder) GoString() string {
return fmt.Sprintf("*%#v", *b)
}
func (p *Provisioner) GoString() string {
return fmt.Sprintf("*%#v", *p)
}
func (p *PostProcessor) GoString() string {
return fmt.Sprintf("*%#v", *p)
}
func (v *Variable) GoString() string {
return fmt.Sprintf("*%#v", *v)
}
|