github.com/jerryclinesmith/packer@v0.3.7/packer/build.go (about) 1 package packer 2 3 import ( 4 "fmt" 5 "log" 6 "sync" 7 ) 8 9 const ( 10 // This is the key in configurations that is set to the name of the 11 // build. 12 BuildNameConfigKey = "packer_build_name" 13 14 // This is the key in the configuration that is set to the type 15 // of the builder that is run. This is useful for provisioners and 16 // such who want to make use of this. 17 BuilderTypeConfigKey = "packer_builder_type" 18 19 // This is the key in configurations that is set to "true" when Packer 20 // debugging is enabled. 21 DebugConfigKey = "packer_debug" 22 23 // This is the key in configurations that is set to "true" when Packer 24 // force build is enabled. 25 ForceConfigKey = "packer_force" 26 27 // This key contains a map[string]string of the user variables for 28 // template processing. 29 UserVariablesConfigKey = "packer_user_variables" 30 ) 31 32 // A Build represents a single job within Packer that is responsible for 33 // building some machine image artifact. Builds are meant to be parallelized. 34 type Build interface { 35 // Name is the name of the build. This is unique across a single template, 36 // but not absolutely unique. This is meant more to describe to the user 37 // what is being built rather than being a unique identifier. 38 Name() string 39 40 // Prepare configures the various components of this build and reports 41 // any errors in doing so (such as syntax errors, validation errors, etc.) 42 Prepare(v map[string]string) error 43 44 // Run runs the actual builder, returning an artifact implementation 45 // of what is built. If anything goes wrong, an error is returned. 46 Run(Ui, Cache) ([]Artifact, error) 47 48 // Cancel will cancel a running build. This will block until the build 49 // is actually completely cancelled. 50 Cancel() 51 52 // SetDebug will enable/disable debug mode. Debug mode is always 53 // enabled by adding the additional key "packer_debug" to boolean 54 // true in the configuration of the various components. This must 55 // be called prior to Prepare. 56 // 57 // When SetDebug is set to true, parallelism between builds is 58 // strictly prohibited. 59 SetDebug(bool) 60 61 // SetForce will enable/disable forcing a build when artifacts exist. 62 // 63 // When SetForce is set to true, existing artifacts from the build are 64 // deleted prior to the build. 65 SetForce(bool) 66 } 67 68 // A build struct represents a single build job, the result of which should 69 // be a single machine image artifact. This artifact may be comprised of 70 // multiple files, of course, but it should be for only a single provider 71 // (such as VirtualBox, EC2, etc.). 72 type coreBuild struct { 73 name string 74 builder Builder 75 builderConfig interface{} 76 builderType string 77 hooks map[string][]Hook 78 postProcessors [][]coreBuildPostProcessor 79 provisioners []coreBuildProvisioner 80 variables map[string]coreBuildVariable 81 82 debug bool 83 force bool 84 l sync.Mutex 85 prepareCalled bool 86 } 87 88 // Keeps track of the post-processor and the configuration of the 89 // post-processor used within a build. 90 type coreBuildPostProcessor struct { 91 processor PostProcessor 92 processorType string 93 config map[string]interface{} 94 keepInputArtifact bool 95 } 96 97 // Keeps track of the provisioner and the configuration of the provisioner 98 // within the build. 99 type coreBuildProvisioner struct { 100 provisioner Provisioner 101 config []interface{} 102 } 103 104 // A user-variable that is part of a single build. 105 type coreBuildVariable struct { 106 Default string 107 Required bool 108 } 109 110 // Returns the name of the build. 111 func (b *coreBuild) Name() string { 112 return b.name 113 } 114 115 // Prepare prepares the build by doing some initialization for the builder 116 // and any hooks. This _must_ be called prior to Run. The parameter is the 117 // overrides for the variables within the template (if any). 118 func (b *coreBuild) Prepare(userVars map[string]string) (err error) { 119 b.l.Lock() 120 defer b.l.Unlock() 121 122 if b.prepareCalled { 123 panic("prepare already called") 124 } 125 126 b.prepareCalled = true 127 128 // Compile the variables 129 varErrs := make([]error, 0) 130 variables := make(map[string]string) 131 for k, v := range b.variables { 132 variables[k] = v.Default 133 134 if v.Required { 135 if _, ok := userVars[k]; !ok { 136 varErrs = append(varErrs, 137 fmt.Errorf("Required user variable '%s' not set", k)) 138 } 139 } 140 } 141 142 if userVars != nil { 143 for k, v := range userVars { 144 if _, ok := variables[k]; !ok { 145 varErrs = append( 146 varErrs, fmt.Errorf("Unknown user variable: %s", k)) 147 continue 148 } 149 150 variables[k] = v 151 } 152 } 153 154 // If there were any problem with variables, return an error right 155 // away because we can't be certain anything else will actually work. 156 if len(varErrs) > 0 { 157 return &MultiError{ 158 Errors: varErrs, 159 } 160 } 161 162 packerConfig := map[string]interface{}{ 163 BuildNameConfigKey: b.name, 164 BuilderTypeConfigKey: b.builderType, 165 DebugConfigKey: b.debug, 166 ForceConfigKey: b.force, 167 UserVariablesConfigKey: variables, 168 } 169 170 // Prepare the builder 171 err = b.builder.Prepare(b.builderConfig, packerConfig) 172 if err != nil { 173 log.Printf("Build '%s' prepare failure: %s\n", b.name, err) 174 return 175 } 176 177 // Prepare the provisioners 178 for _, coreProv := range b.provisioners { 179 configs := make([]interface{}, len(coreProv.config), len(coreProv.config)+1) 180 copy(configs, coreProv.config) 181 configs = append(configs, packerConfig) 182 183 if err = coreProv.provisioner.Prepare(configs...); err != nil { 184 return 185 } 186 } 187 188 // Prepare the post-processors 189 for _, ppSeq := range b.postProcessors { 190 for _, corePP := range ppSeq { 191 err = corePP.processor.Configure(corePP.config, packerConfig) 192 if err != nil { 193 return 194 } 195 } 196 } 197 198 return 199 } 200 201 // Runs the actual build. Prepare must be called prior to running this. 202 func (b *coreBuild) Run(originalUi Ui, cache Cache) ([]Artifact, error) { 203 if !b.prepareCalled { 204 panic("Prepare must be called first") 205 } 206 207 // Copy the hooks 208 hooks := make(map[string][]Hook) 209 for hookName, hookList := range b.hooks { 210 hooks[hookName] = make([]Hook, len(hookList)) 211 copy(hooks[hookName], hookList) 212 } 213 214 // Add a hook for the provisioners if we have provisioners 215 if len(b.provisioners) > 0 { 216 provisioners := make([]Provisioner, len(b.provisioners)) 217 for i, p := range b.provisioners { 218 provisioners[i] = p.provisioner 219 } 220 221 if _, ok := hooks[HookProvision]; !ok { 222 hooks[HookProvision] = make([]Hook, 0, 1) 223 } 224 225 hooks[HookProvision] = append(hooks[HookProvision], &ProvisionHook{ 226 Provisioners: provisioners, 227 }) 228 } 229 230 hook := &DispatchHook{Mapping: hooks} 231 artifacts := make([]Artifact, 0, 1) 232 233 // The builder just has a normal Ui, but targetted 234 builderUi := &TargettedUi{ 235 Target: b.Name(), 236 Ui: originalUi, 237 } 238 239 log.Printf("Running builder: %s", b.builderType) 240 builderArtifact, err := b.builder.Run(builderUi, hook, cache) 241 if err != nil { 242 return nil, err 243 } 244 245 // If there was no result, don't worry about running post-processors 246 // because there is nothing they can do, just return. 247 if builderArtifact == nil { 248 return nil, nil 249 } 250 251 errors := make([]error, 0) 252 keepOriginalArtifact := len(b.postProcessors) == 0 253 254 // Run the post-processors 255 PostProcessorRunSeqLoop: 256 for _, ppSeq := range b.postProcessors { 257 priorArtifact := builderArtifact 258 for i, corePP := range ppSeq { 259 ppUi := &TargettedUi{ 260 Target: fmt.Sprintf("%s (%s)", b.Name(), corePP.processorType), 261 Ui: originalUi, 262 } 263 264 builderUi.Say(fmt.Sprintf("Running post-processor: %s", corePP.processorType)) 265 artifact, keep, err := corePP.processor.PostProcess(ppUi, priorArtifact) 266 if err != nil { 267 errors = append(errors, fmt.Errorf("Post-processor failed: %s", err)) 268 continue PostProcessorRunSeqLoop 269 } 270 271 if artifact == nil { 272 log.Println("Nil artifact, halting post-processor chain.") 273 continue PostProcessorRunSeqLoop 274 } 275 276 keep = keep || corePP.keepInputArtifact 277 if i == 0 { 278 // This is the first post-processor. We handle deleting 279 // previous artifacts a bit different because multiple 280 // post-processors may be using the original and need it. 281 if !keepOriginalArtifact && keep { 282 log.Printf( 283 "Flagging to keep original artifact from post-processor '%s'", 284 corePP.processorType) 285 keepOriginalArtifact = true 286 } 287 } else { 288 // We have a prior artifact. If we want to keep it, we append 289 // it to the results list. Otherwise, we destroy it. 290 if keep { 291 artifacts = append(artifacts, priorArtifact) 292 } else { 293 log.Printf("Deleting prior artifact from post-processor '%s'", corePP.processorType) 294 if err := priorArtifact.Destroy(); err != nil { 295 errors = append(errors, fmt.Errorf("Failed cleaning up prior artifact: %s", err)) 296 } 297 } 298 } 299 300 priorArtifact = artifact 301 } 302 303 // Add on the last artifact to the results 304 if priorArtifact != nil { 305 artifacts = append(artifacts, priorArtifact) 306 } 307 } 308 309 if keepOriginalArtifact { 310 artifacts = append(artifacts, nil) 311 copy(artifacts[1:], artifacts) 312 artifacts[0] = builderArtifact 313 } else { 314 log.Printf("Deleting original artifact for build '%s'", b.name) 315 if err := builderArtifact.Destroy(); err != nil { 316 errors = append(errors, fmt.Errorf("Error destroying builder artifact: %s", err)) 317 } 318 } 319 320 if len(errors) > 0 { 321 err = &MultiError{errors} 322 } 323 324 return artifacts, err 325 } 326 327 func (b *coreBuild) SetDebug(val bool) { 328 if b.prepareCalled { 329 panic("prepare has already been called") 330 } 331 332 b.debug = val 333 } 334 335 func (b *coreBuild) SetForce(val bool) { 336 if b.prepareCalled { 337 panic("prepare has already been called") 338 } 339 340 b.force = val 341 } 342 343 // Cancels the build if it is running. 344 func (b *coreBuild) Cancel() { 345 b.builder.Cancel() 346 }