forked from hashicorp/packer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
template.go
201 lines (167 loc) · 4.75 KB
/
template.go
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
package template
import (
"errors"
"fmt"
"time"
"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
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"`
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)
}