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