github.com/phobos182/packer@v0.2.3-0.20130819023704-c84d2aeffc68/post-processor/vagrant/post-processor.go (about)

     1  // vagrant implements the packer.PostProcessor interface and adds a
     2  // post-processor that turns artifacts of known builders into Vagrant
     3  // boxes.
     4  package vagrant
     5  
     6  import (
     7  	"fmt"
     8  	"github.com/mitchellh/mapstructure"
     9  	"github.com/mitchellh/packer/packer"
    10  	"log"
    11  	"text/template"
    12  )
    13  
    14  var builtins = map[string]string{
    15  	"mitchellh.amazonebs":  "aws",
    16  	"mitchellh.virtualbox": "virtualbox",
    17  	"mitchellh.vmware":     "vmware",
    18  }
    19  
    20  type Config struct {
    21  	OutputPath string `mapstructure:"output"`
    22  }
    23  
    24  type PostProcessor struct {
    25  	config     Config
    26  	premade    map[string]packer.PostProcessor
    27  	rawConfigs []interface{}
    28  }
    29  
    30  func (p *PostProcessor) Configure(raws ...interface{}) error {
    31  	// Store the raw configs for usage later
    32  	p.rawConfigs = raws
    33  
    34  	for _, raw := range raws {
    35  		err := mapstructure.Decode(raw, &p.config)
    36  		if err != nil {
    37  			return err
    38  		}
    39  	}
    40  
    41  	ppExtraConfig := make(map[string]interface{})
    42  	if p.config.OutputPath == "" {
    43  		p.config.OutputPath = "packer_{{ .BuildName }}_{{.Provider}}.box"
    44  		ppExtraConfig["output"] = p.config.OutputPath
    45  	}
    46  
    47  	_, err := template.New("output").Parse(p.config.OutputPath)
    48  	if err != nil {
    49  		return fmt.Errorf("output invalid template: %s", err)
    50  	}
    51  
    52  	// Store the extra configuration for post-processors
    53  	p.rawConfigs = append(p.rawConfigs, ppExtraConfig)
    54  
    55  	// TODO(mitchellh): Properly handle multiple raw configs
    56  	var mapConfig map[string]interface{}
    57  	if err := mapstructure.Decode(raws[0], &mapConfig); err != nil {
    58  		return err
    59  	}
    60  
    61  	p.premade = make(map[string]packer.PostProcessor)
    62  	errors := make([]error, 0)
    63  	for k, raw := range mapConfig {
    64  		pp := keyToPostProcessor(k)
    65  		if pp == nil {
    66  			continue
    67  		}
    68  
    69  		// Create the proper list of configurations
    70  		ppConfigs := make([]interface{}, 0, len(p.rawConfigs)+1)
    71  		copy(ppConfigs, p.rawConfigs)
    72  		ppConfigs = append(ppConfigs, raw)
    73  
    74  		if err := pp.Configure(ppConfigs...); err != nil {
    75  			errors = append(errors, err)
    76  		}
    77  
    78  		p.premade[k] = pp
    79  	}
    80  
    81  	if len(errors) > 0 {
    82  		return &packer.MultiError{errors}
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
    89  	ppName, ok := builtins[artifact.BuilderId()]
    90  	if !ok {
    91  		return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
    92  	}
    93  
    94  	// Use the premade PostProcessor if we have one. Otherwise, we
    95  	// create it and configure it here.
    96  	pp, ok := p.premade[ppName]
    97  	if !ok {
    98  		log.Printf("Premade post-processor for '%s' not found. Creating.", ppName)
    99  		pp = keyToPostProcessor(ppName)
   100  		if pp == nil {
   101  			return nil, false, fmt.Errorf("Vagrant box post-processor not found: %s", ppName)
   102  		}
   103  
   104  		if err := pp.Configure(p.rawConfigs...); err != nil {
   105  			return nil, false, err
   106  		}
   107  	}
   108  
   109  	ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", ppName))
   110  	return pp.PostProcess(ui, artifact)
   111  }
   112  
   113  func keyToPostProcessor(key string) packer.PostProcessor {
   114  	switch key {
   115  	case "aws":
   116  		return new(AWSBoxPostProcessor)
   117  	case "virtualbox":
   118  		return new(VBoxBoxPostProcessor)
   119  	case "vmware":
   120  		return new(VMwareBoxPostProcessor)
   121  	default:
   122  		return nil
   123  	}
   124  }