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 }