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