From 5e2f08de70a3dd9a3d47b1aa3729e72ee94cbe07 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 19 Dec 2013 14:44:15 -0800 Subject: [PATCH] post-processor/vagrant: do overrides --- post-processor/vagrant/post-processor.go | 129 +++++++++++------- post-processor/vagrant/post-processor_test.go | 44 +++++- .../post-processors/vagrant.html.markdown | 29 ++++ 3 files changed, 148 insertions(+), 54 deletions(-) diff --git a/post-processor/vagrant/post-processor.go b/post-processor/vagrant/post-processor.go index 7772d69c0..2329eba3c 100644 --- a/post-processor/vagrant/post-processor.go +++ b/post-processor/vagrant/post-processor.go @@ -26,66 +26,39 @@ var builtins = map[string]string{ type Config struct { common.PackerConfig `mapstructure:",squash"` + CompressionLevel int `mapstructure:"compression_level"` Include []string `mapstructure:"include"` OutputPath string `mapstructure:"output"` - VagrantfileTemplate string `mapstructure:"vagrantfile_template"` - CompressionLevel int `mapstructure:"compression_level"` + Override map[string]interface{} + VagrantfileTemplate string `mapstructure:"vagrantfile_template"` tpl *packer.ConfigTemplate } type PostProcessor struct { - config Config + configs map[string]*Config } func (p *PostProcessor) Configure(raws ...interface{}) error { - md, err := common.DecodeConfig(&p.config, raws...) - if err != nil { + p.configs = make(map[string]*Config) + p.configs[""] = new(Config) + if err := p.configureSingle(p.configs[""], raws...); err != nil { return err } - p.config.tpl, err = packer.NewConfigTemplate() - if err != nil { - return err - } - p.config.tpl.UserVars = p.config.PackerUserVars + // Go over any of the provider-specific overrides and load those up. + for name, override := range p.configs[""].Override { + subRaws := make([]interface{}, len(raws)+1) + copy(subRaws, raws) + subRaws[len(raws)] = override - // 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 + config := new(Config) + p.configs[name] = config + if err := p.configureSingle(config, subRaws...); err != nil { + return fmt.Errorf("Error configuring %s: %s", name, err) } } - if !found { - p.config.CompressionLevel = flate.DefaultCompression - } - - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - - validates := map[string]*string{ - "output": &p.config.OutputPath, - "vagrantfile_template": &p.config.VagrantfileTemplate, - } - - for n, ptr := range validates { - if err := p.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 } @@ -102,11 +75,16 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac 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)) - outputPath, err := p.config.tpl.Process(p.config.OutputPath, &outputPathTemplate{ + outputPath, err := config.tpl.Process(config.OutputPath, &outputPathTemplate{ ArtifactId: artifact.Id(), - BuildName: p.config.PackerBuildName, + BuildName: config.PackerBuildName, Provider: name, }) if err != nil { @@ -121,7 +99,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac defer os.RemoveAll(dir) // 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)) dst := filepath.Join(dir, filepath.Base(src)) if err := CopyContents(dst, src); err != nil { @@ -143,10 +121,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac // Write our Vagrantfile var customVagrantfile string - if p.config.VagrantfileTemplate != "" { + if config.VagrantfileTemplate != "" { ui.Message(fmt.Sprintf( - "Using custom Vagrantfile: %s", p.config.VagrantfileTemplate)) - customBytes, err := ioutil.ReadFile(p.config.VagrantfileTemplate) + "Using custom Vagrantfile: %s", config.VagrantfileTemplate)) + customBytes, err := ioutil.ReadFile(config.VagrantfileTemplate) if err != nil { return nil, false, err } @@ -170,13 +148,64 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac } // 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, 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 { switch name { case "virtualbox": diff --git a/post-processor/vagrant/post-processor_test.go b/post-processor/vagrant/post-processor_test.go index 552c7ba02..0ef151ebe 100644 --- a/post-processor/vagrant/post-processor_test.go +++ b/post-processor/vagrant/post-processor_test.go @@ -42,8 +42,9 @@ func TestPostProcessorPrepare_compressionLevel(t *testing.T) { t.Fatalf("err: %s", err) } - if p.config.CompressionLevel != flate.DefaultCompression { - t.Fatalf("bad: %#v", p.config.CompressionLevel) + config := p.configs[""] + if config.CompressionLevel != flate.DefaultCompression { + t.Fatalf("bad: %#v", config.CompressionLevel) } // Set @@ -53,8 +54,9 @@ func TestPostProcessorPrepare_compressionLevel(t *testing.T) { t.Fatalf("err: %s", err) } - if p.config.CompressionLevel != 7 { - t.Fatalf("bad: %#v", p.config.CompressionLevel) + config = p.configs[""] + if config.CompressionLevel != 7 { + t.Fatalf("bad: %#v", config.CompressionLevel) } } @@ -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) { artifact := &packer.MockArtifact{ BuilderIdValue: "invalid.packer", diff --git a/website/source/docs/post-processors/vagrant.html.markdown b/website/source/docs/post-processors/vagrant.html.markdown index 2b5f4368f..d83a2b265 100644 --- a/website/source/docs/post-processors/vagrant.html.markdown +++ b/website/source/docs/post-processors/vagrant.html.markdown @@ -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 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`.