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{
type Config struct {
common.PackerConfig `mapstructure:",squash"`
CompressionLevel int `mapstructure:"compression_level"`
Include []string `mapstructure:"include"`
OutputPath string `mapstructure:"output"`
Override map[string]interface{}
VagrantfileTemplate string `mapstructure:"vagrantfile_template"`
CompressionLevel int `mapstructure:"compression_level"`
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 {
return err
}
p.config.tpl, err = packer.NewConfigTemplate()
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.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{
"output": &p.config.OutputPath,
"vagrantfile_template": &p.config.VagrantfileTemplate,
}
// 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
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))
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 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":
......
......@@ -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",
......
......@@ -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`.
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