github.com/rothwerx/packer@v0.9.0/template/template.go (about) 1 package template 2 3 import ( 4 "errors" 5 "fmt" 6 "time" 7 8 "github.com/hashicorp/go-multierror" 9 ) 10 11 // Template represents the parsed template that is used to configure 12 // Packer builds. 13 type Template struct { 14 // Path is the path to the template. This will be blank if Parse is 15 // used, but will be automatically populated by ParseFile. 16 Path string 17 18 Description string 19 MinVersion string 20 21 Variables map[string]*Variable 22 Builders map[string]*Builder 23 Provisioners []*Provisioner 24 PostProcessors [][]*PostProcessor 25 Push Push 26 27 // RawContents is just the raw data for this template 28 RawContents []byte 29 } 30 31 // Builder represents a builder configured in the template 32 type Builder struct { 33 Name string 34 Type string 35 Config map[string]interface{} 36 } 37 38 // PostProcessor represents a post-processor within the template. 39 type PostProcessor struct { 40 OnlyExcept `mapstructure:",squash"` 41 42 Type string 43 KeepInputArtifact bool `mapstructure:"keep_input_artifact"` 44 Config map[string]interface{} 45 } 46 47 // Provisioner represents a provisioner within the template. 48 type Provisioner struct { 49 OnlyExcept `mapstructure:",squash"` 50 51 Type string 52 Config map[string]interface{} 53 Override map[string]interface{} 54 PauseBefore time.Duration `mapstructure:"pause_before"` 55 } 56 57 // Push represents the configuration for pushing the template to Atlas. 58 type Push struct { 59 Name string 60 Address string 61 BaseDir string `mapstructure:"base_dir"` 62 Include []string 63 Exclude []string 64 Token string 65 VCS bool 66 } 67 68 // Variable represents a variable within the template 69 type Variable struct { 70 Default string 71 Required bool 72 } 73 74 // OnlyExcept is a struct that is meant to be embedded that contains the 75 // logic required for "only" and "except" meta-parameters. 76 type OnlyExcept struct { 77 Only []string 78 Except []string 79 } 80 81 //------------------------------------------------------------------- 82 // Functions 83 //------------------------------------------------------------------- 84 85 // Validate does some basic validation of the template on top of the 86 // validation that occurs while parsing. If possible, we try to defer 87 // validation to here. The validation errors that occur during parsing 88 // are the minimal necessary to make sure parsing builds a reasonable 89 // Template structure. 90 func (t *Template) Validate() error { 91 var err error 92 93 // At least one builder must be defined 94 if len(t.Builders) == 0 { 95 err = multierror.Append(err, errors.New( 96 "at least one builder must be defined")) 97 } 98 99 // Verify that the provisioner overrides target builders that exist 100 for i, p := range t.Provisioners { 101 // Validate only/except 102 if verr := p.OnlyExcept.Validate(t); verr != nil { 103 for _, e := range multierror.Append(verr).Errors { 104 err = multierror.Append(err, fmt.Errorf( 105 "provisioner %d: %s", i+1, e)) 106 } 107 } 108 109 // Validate overrides 110 for name, _ := range p.Override { 111 if _, ok := t.Builders[name]; !ok { 112 err = multierror.Append(err, fmt.Errorf( 113 "provisioner %d: override '%s' doesn't exist", 114 i+1, name)) 115 } 116 } 117 } 118 119 // Verify post-processors 120 for i, chain := range t.PostProcessors { 121 for j, p := range chain { 122 // Validate only/except 123 if verr := p.OnlyExcept.Validate(t); verr != nil { 124 for _, e := range multierror.Append(verr).Errors { 125 err = multierror.Append(err, fmt.Errorf( 126 "post-processor %d.%d: %s", i+1, j+1, e)) 127 } 128 } 129 } 130 } 131 132 return err 133 } 134 135 // Skip says whether or not to skip the build with the given name. 136 func (o *OnlyExcept) Skip(n string) bool { 137 if len(o.Only) > 0 { 138 for _, v := range o.Only { 139 if v == n { 140 return false 141 } 142 } 143 144 return true 145 } 146 147 if len(o.Except) > 0 { 148 for _, v := range o.Except { 149 if v == n { 150 return true 151 } 152 } 153 154 return false 155 } 156 157 return false 158 } 159 160 // Validate validates that the OnlyExcept settings are correct for a thing. 161 func (o *OnlyExcept) Validate(t *Template) error { 162 if len(o.Only) > 0 && len(o.Except) > 0 { 163 return errors.New("only one of 'only' or 'except' may be specified") 164 } 165 166 var err error 167 for _, n := range o.Only { 168 if _, ok := t.Builders[n]; !ok { 169 err = multierror.Append(err, fmt.Errorf( 170 "'only' specified builder '%s' not found", n)) 171 } 172 } 173 for _, n := range o.Except { 174 if _, ok := t.Builders[n]; !ok { 175 err = multierror.Append(err, fmt.Errorf( 176 "'except' specified builder '%s' not found", n)) 177 } 178 } 179 180 return err 181 } 182 183 //------------------------------------------------------------------- 184 // GoStringer 185 //------------------------------------------------------------------- 186 187 func (b *Builder) GoString() string { 188 return fmt.Sprintf("*%#v", *b) 189 } 190 191 func (p *Provisioner) GoString() string { 192 return fmt.Sprintf("*%#v", *p) 193 } 194 195 func (p *PostProcessor) GoString() string { 196 return fmt.Sprintf("*%#v", *p) 197 } 198 199 func (v *Variable) GoString() string { 200 return fmt.Sprintf("*%#v", *v) 201 }