Commit 5e2f08de authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

post-processor/vagrant: do overrides

parent 84f8c0bf
...@@ -26,66 +26,39 @@ var builtins = map[string]string{ ...@@ -26,66 +26,39 @@ var builtins = map[string]string{
type Config struct { type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
CompressionLevel int `mapstructure:"compression_level"`
Include []string `mapstructure:"include"` Include []string `mapstructure:"include"`
OutputPath string `mapstructure:"output"` OutputPath string `mapstructure:"output"`
VagrantfileTemplate string `mapstructure:"vagrantfile_template"` Override map[string]interface{}
CompressionLevel int `mapstructure:"compression_level"` VagrantfileTemplate string `mapstructure:"vagrantfile_template"`
tpl *packer.ConfigTemplate tpl *packer.ConfigTemplate
} }
type PostProcessor struct { type PostProcessor struct {
config Config configs map[string]*Config
} }
func (p *PostProcessor) Configure(raws ...interface{}) error { func (p *PostProcessor) Configure(raws ...interface{}) error {
md, err := common.DecodeConfig(&p.config, raws...) p.configs = make(map[string]*Config)
if err != nil { p.configs[""] = new(Config)
return err if err := p.configureSingle(p.configs[""], raws...); err != nil {
}
p.config.tpl, err = packer.NewConfigTemplate()
if err != nil {
return err return err
} }
p.config.tpl.UserVars = p.config.PackerUserVars
// Defaults
if p.config.OutputPath == "" {
p.config.OutputPath = "packer_{{ .BuildName }}_{{.Provider}}.box"
}
found := false
for _, k := range md.Keys {
if k == "compression_level" {
found = true
break
}
}
if !found {
p.config.CompressionLevel = flate.DefaultCompression
}
// Accumulate any errors
errs := common.CheckUnusedConfig(md)
validates := map[string]*string{ // Go over any of the provider-specific overrides and load those up.
"output": &p.config.OutputPath, for name, override := range p.configs[""].Override {
"vagrantfile_template": &p.config.VagrantfileTemplate, subRaws := make([]interface{}, len(raws)+1)
} copy(subRaws, raws)
subRaws[len(raws)] = override
for n, ptr := range validates { config := new(Config)
if err := p.config.tpl.Validate(*ptr); err != nil { p.configs[name] = config
errs = packer.MultiErrorAppend( if err := p.configureSingle(config, subRaws...); err != nil {
errs, fmt.Errorf("Error parsing %s: %s", n, err)) return fmt.Errorf("Error configuring %s: %s", name, err)
} }
} }
if errs != nil && len(errs.Errors) > 0 {
return errs
}
return nil return nil
} }
...@@ -102,11 +75,16 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ...@@ -102,11 +75,16 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
panic(fmt.Sprintf("bad provider name: %s", name)) panic(fmt.Sprintf("bad provider name: %s", name))
} }
config := p.configs[""]
if specificConfig, ok := p.configs[name]; ok {
config = specificConfig
}
ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", name)) ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", name))
outputPath, err := p.config.tpl.Process(p.config.OutputPath, &outputPathTemplate{ outputPath, err := config.tpl.Process(config.OutputPath, &outputPathTemplate{
ArtifactId: artifact.Id(), ArtifactId: artifact.Id(),
BuildName: p.config.PackerBuildName, BuildName: config.PackerBuildName,
Provider: name, Provider: name,
}) })
if err != nil { if err != nil {
...@@ -121,7 +99,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ...@@ -121,7 +99,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
// Copy all of the includes files into the temporary directory // Copy all of the includes files into the temporary directory
for _, src := range p.config.Include { for _, src := range config.Include {
ui.Message(fmt.Sprintf("Copying from include: %s", src)) ui.Message(fmt.Sprintf("Copying from include: %s", src))
dst := filepath.Join(dir, filepath.Base(src)) dst := filepath.Join(dir, filepath.Base(src))
if err := CopyContents(dst, src); err != nil { if err := CopyContents(dst, src); err != nil {
...@@ -143,10 +121,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ...@@ -143,10 +121,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
// Write our Vagrantfile // Write our Vagrantfile
var customVagrantfile string var customVagrantfile string
if p.config.VagrantfileTemplate != "" { if config.VagrantfileTemplate != "" {
ui.Message(fmt.Sprintf( ui.Message(fmt.Sprintf(
"Using custom Vagrantfile: %s", p.config.VagrantfileTemplate)) "Using custom Vagrantfile: %s", config.VagrantfileTemplate))
customBytes, err := ioutil.ReadFile(p.config.VagrantfileTemplate) customBytes, err := ioutil.ReadFile(config.VagrantfileTemplate)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
...@@ -170,13 +148,64 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ...@@ -170,13 +148,64 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
} }
// Create the box // Create the box
if err := DirToBox(outputPath, dir, ui, p.config.CompressionLevel); err != nil { if err := DirToBox(outputPath, dir, ui, config.CompressionLevel); err != nil {
return nil, false, err return nil, false, err
} }
return nil, false, nil return nil, false, nil
} }
func (p *PostProcessor) configureSingle(config *Config, raws ...interface{}) error {
md, err := common.DecodeConfig(config, raws...)
if err != nil {
return err
}
config.tpl, err = packer.NewConfigTemplate()
if err != nil {
return err
}
config.tpl.UserVars = config.PackerUserVars
// Defaults
if config.OutputPath == "" {
config.OutputPath = "packer_{{ .BuildName }}_{{.Provider}}.box"
}
found := false
for _, k := range md.Keys {
if k == "compression_level" {
found = true
break
}
}
if !found {
config.CompressionLevel = flate.DefaultCompression
}
// Accumulate any errors
errs := common.CheckUnusedConfig(md)
validates := map[string]*string{
"output": &config.OutputPath,
"vagrantfile_template": &config.VagrantfileTemplate,
}
for n, ptr := range validates {
if err := config.tpl.Validate(*ptr); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error parsing %s: %s", n, err))
}
}
if errs != nil && len(errs.Errors) > 0 {
return errs
}
return nil
}
func providerForName(name string) Provider { func providerForName(name string) Provider {
switch name { switch name {
case "virtualbox": case "virtualbox":
......
...@@ -42,8 +42,9 @@ func TestPostProcessorPrepare_compressionLevel(t *testing.T) { ...@@ -42,8 +42,9 @@ func TestPostProcessorPrepare_compressionLevel(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if p.config.CompressionLevel != flate.DefaultCompression { config := p.configs[""]
t.Fatalf("bad: %#v", p.config.CompressionLevel) if config.CompressionLevel != flate.DefaultCompression {
t.Fatalf("bad: %#v", config.CompressionLevel)
} }
// Set // Set
...@@ -53,8 +54,9 @@ func TestPostProcessorPrepare_compressionLevel(t *testing.T) { ...@@ -53,8 +54,9 @@ func TestPostProcessorPrepare_compressionLevel(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if p.config.CompressionLevel != 7 { config = p.configs[""]
t.Fatalf("bad: %#v", p.config.CompressionLevel) if config.CompressionLevel != 7 {
t.Fatalf("bad: %#v", config.CompressionLevel)
} }
} }
...@@ -77,6 +79,40 @@ func TestPostProcessorPrepare_outputPath(t *testing.T) { ...@@ -77,6 +79,40 @@ func TestPostProcessorPrepare_outputPath(t *testing.T) {
} }
} }
func TestPostProcessorPrepare_subConfigs(t *testing.T) {
var p PostProcessor
// Default
c := testConfig()
c["compression_level"] = 42
c["vagrantfile_template"] = "foo"
c["override"] = map[string]interface{}{
"aws": map[string]interface{}{
"compression_level": 7,
},
}
err := p.Configure(c)
if err != nil {
t.Fatalf("err: %s", err)
}
if p.configs[""].CompressionLevel != 42 {
t.Fatalf("bad: %#v", p.configs[""].CompressionLevel)
}
if p.configs[""].VagrantfileTemplate != "foo" {
t.Fatalf("bad: %#v", p.configs[""].VagrantfileTemplate)
}
if p.configs["aws"].CompressionLevel != 7 {
t.Fatalf("bad: %#v", p.configs["aws"].CompressionLevel)
}
if p.configs["aws"].VagrantfileTemplate != "foo" {
t.Fatalf("bad: %#v", p.configs["aws"].VagrantfileTemplate)
}
}
func TestPostProcessorPostProcess_badId(t *testing.T) { func TestPostProcessorPostProcess_badId(t *testing.T) {
artifact := &packer.MockArtifact{ artifact := &packer.MockArtifact{
BuilderIdValue: "invalid.packer", BuilderIdValue: "invalid.packer",
......
...@@ -68,3 +68,32 @@ below, with more details about certain options in following sections. ...@@ -68,3 +68,32 @@ below, with more details about certain options in following sections.
* `vagrantfile_template` (string) - Path to a template to use for the * `vagrantfile_template` (string) - Path to a template to use for the
Vagrantfile that is packaged with the box. Vagrantfile that is packaged with the box.
## Provider-Specific Overrides
If you have a Packer template with multiple builder types within it,
you may want to configure the box creation for each type a little differently.
For example, the contents of the Vagrantfile for a Vagrant box for AWS might
be different from the contents of the Vagrantfile you want for VMware.
The post-processor lets you do this.
Specify overrides within the `override` configuration by provider name:
```json
{
"type": "vagrant",
"compression_level": 1,
"override": {
"vmware": {
"compression_level": 0
}
}
}
```
In the example above, the compression level will be set to 1 except for
VMware, where it will be set to 0.
The available provider names are: `aws`, `digitalocean`, `virtualbox`,
and `vmware`.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment