From b29d0b43781d5b9d245e40a6425a38c645617e67 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Mon, 21 Nov 2016 11:04:16 +0300 Subject: [PATCH 1/4] post-processor/manifest: fixes interpolation of output * rename `filename` to `output` for consistent with other post-processors * interpolate output with variables Signed-off-by: Vasiliy Tolstov --- post-processor/manifest/post-processor.go | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/post-processor/manifest/post-processor.go b/post-processor/manifest/post-processor.go index 7b4507cf6..5a75bd34c 100644 --- a/post-processor/manifest/post-processor.go +++ b/post-processor/manifest/post-processor.go @@ -18,9 +18,9 @@ import ( type Config struct { common.PackerConfig `mapstructure:",squash"` - Filename string `mapstructure:"filename"` - StripPath bool `mapstructure:"strip_path"` - ctx interpolate.Context + OutputPath string `mapstructure:"output"` + StripPath bool `mapstructure:"strip_path"` + ctx interpolate.Context } type PostProcessor struct { @@ -44,8 +44,12 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { return err } - if p.config.Filename == "" { - p.config.Filename = "packer-manifest.json" + if p.config.OutputPath == "" { + p.config.OutputPath = "packer-manifest.json" + } + + if err = interpolate.Validate(p.config.OutputPath, &p.config.ctx); err != nil { + return fmt.Errorf("Error parsing target template: %s", err) } return nil @@ -85,7 +89,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, source packer.Artifact) (packe // Create a lock file with exclusive access. If this fails we will retry // after a delay. - lockFilename := p.config.Filename + ".lock" + lockFilename := p.config.OutputPath + ".lock" for i := 0; i < 3; i++ { // The file should not be locked for very long so we'll keep this short. time.Sleep((time.Duration(i) * 200 * time.Millisecond)) @@ -97,20 +101,17 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, source packer.Artifact) (packe } defer os.Remove(lockFilename) - // TODO fix error on first run: - // * Post-processor failed: open packer-manifest.json: no such file or directory - // // Read the current manifest file from disk contents := []byte{} - if contents, err = ioutil.ReadFile(p.config.Filename); err != nil && !os.IsNotExist(err) { - return source, true, fmt.Errorf("Unable to open %s for reading: %s", p.config.Filename, err) + if contents, err = ioutil.ReadFile(p.config.OutputPath); err != nil && !os.IsNotExist(err) { + return source, true, fmt.Errorf("Unable to open %s for reading: %s", p.config.OutputPath, err) } // Parse the manifest file JSON, if we have one manifestFile := &ManifestFile{} if len(contents) > 0 { if err = json.Unmarshal(contents, manifestFile); err != nil { - return source, true, fmt.Errorf("Unable to parse content from %s: %s", p.config.Filename, err) + return source, true, fmt.Errorf("Unable to parse content from %s: %s", p.config.OutputPath, err) } } @@ -126,8 +127,8 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, source packer.Artifact) (packe // Write JSON to disk if out, err := json.MarshalIndent(manifestFile, "", " "); err == nil { - if err = ioutil.WriteFile(p.config.Filename, out, 0664); err != nil { - return source, true, fmt.Errorf("Unable to write %s: %s", p.config.Filename, err) + if err = ioutil.WriteFile(p.config.OutputPath, out, 0664); err != nil { + return source, true, fmt.Errorf("Unable to write %s: %s", p.config.OutputPath, err) } } else { return source, true, fmt.Errorf("Unable to marshal JSON %s", err) From e3acd19cb715be30281f5c26856cbb4333511172 Mon Sep 17 00:00:00 2001 From: Matthew Hooker Date: Mon, 21 Nov 2016 15:34:50 -0800 Subject: [PATCH 2/4] add fixer for manifest filename->output --- fix/fixer.go | 2 + fix/fixer_pp_manifest_filename.go | 60 ++++++++++++++++++++++++++ fix/fixer_pp_manifest_filename_test.go | 41 ++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 fix/fixer_pp_manifest_filename.go create mode 100644 fix/fixer_pp_manifest_filename_test.go diff --git a/fix/fixer.go b/fix/fixer.go index 78f58f546..382cd25b8 100644 --- a/fix/fixer.go +++ b/fix/fixer.go @@ -29,6 +29,7 @@ func init() { "parallels-headless": new(FixerParallelsHeadless), "parallels-deprecations": new(FixerParallelsDeprecations), "sshkeypath": new(FixerSSHKeyPath), + "manifest-filename": new(FixerManifestFilename), } FixerOrder = []string{ @@ -41,5 +42,6 @@ func init() { "parallels-headless", "parallels-deprecations", "sshkeypath", + "manifest-filename", } } diff --git a/fix/fixer_pp_manifest_filename.go b/fix/fixer_pp_manifest_filename.go new file mode 100644 index 000000000..923f63c93 --- /dev/null +++ b/fix/fixer_pp_manifest_filename.go @@ -0,0 +1,60 @@ +package fix + +import ( + "fmt" + "github.com/mitchellh/mapstructure" +) + +// FixerManifestFilename renames any Filename to Output +type FixerManifestFilename struct{} + +func (FixerManifestFilename) Fix(input map[string]interface{}) (map[string]interface{}, error) { + + // Our template type we'll use for this fixer only + type template struct { + PostProcessors []map[string]interface{} `mapstructure:"post-processors"` + } + + // Decode the input into our structure, if we can + fmt.Println("Got 0") + var tpl template + if err := mapstructure.Decode(input, &tpl); err != nil { + fmt.Println("Got 1") + return nil, err + } + for _, pp := range tpl.PostProcessors { + ppTypeRaw, ok := pp["type"] + if !ok { + continue + } + + ppType, ok := ppTypeRaw.(string) + if !ok { + continue + } + + if ppType != "manifest" { + continue + } + + filenameRaw, ok := pp["filename"] + if !ok { + continue + } + + filename, ok := filenameRaw.(string) + if !ok { + continue + } + + delete(pp, "filename") + pp["output"] = filename + } + + input["post-processors"] = tpl.PostProcessors + return input, nil +} + +func (FixerManifestFilename) Synopsis() string { + return `Updates "manifest" post-processor so any "filename" field is renamed to "output".` +} diff --git a/fix/fixer_pp_manifest_filename_test.go b/fix/fixer_pp_manifest_filename_test.go new file mode 100644 index 000000000..ed726dfd6 --- /dev/null +++ b/fix/fixer_pp_manifest_filename_test.go @@ -0,0 +1,41 @@ +package fix + +import ( + "reflect" + "testing" +) + +func TestFixerManifestPPFilename_Impl(t *testing.T) { + var _ Fixer = new(FixerVagrantPPOverride) +} + +func TestFixerManifestPPFilename_Fix(t *testing.T) { + var f FixerManifestFilename + + input := map[string]interface{}{ + "post-processors": []map[string]interface{}{ + { + "type": "manifest", + "filename": "foo", + }, + }, + } + + expected := map[string]interface{}{ + "post-processors": []map[string]interface{}{ + { + "type": "manifest", + "output": "foo", + }, + }, + } + + output, err := f.Fix(input) + if err != nil { + t.Fatalf("err: %s", err) + } + + if !reflect.DeepEqual(output, expected) { + t.Fatalf("unexpected: %#v\nexpected: %#v\n", output, expected) + } +} From 70ca8486bab845902b8db985c52f84ca1ec1610c Mon Sep 17 00:00:00 2001 From: Matthew Hooker Date: Mon, 21 Nov 2016 15:35:57 -0800 Subject: [PATCH 3/4] update docs --- website/source/docs/post-processors/manifest.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/source/docs/post-processors/manifest.html.md b/website/source/docs/post-processors/manifest.html.md index 2130c53a4..7de60c0a7 100644 --- a/website/source/docs/post-processors/manifest.html.md +++ b/website/source/docs/post-processors/manifest.html.md @@ -21,7 +21,7 @@ You can specify manifest more than once and write each build to its own file, or ### Optional: -- `filename` (string) The manifest will be written to this file. This defaults to `packer-manifest.json`. +- `output` (string) The manifest will be written to this file. This defaults to `packer-manifest.json`. - `strip_path` (bool) Write only filename without the path to the manifest file. This defaults to false. ### Example Configuration @@ -33,7 +33,7 @@ You can simply add `{"type":"manifest"}` to your post-processor section. Below i "post-processors": [ { "type": "manifest", - "filename": "manifest.json", + "output": "manifest.json", "strip_path": true } ] From 58c5f8262a19a6e0866bc1e33a9232868ec38af2 Mon Sep 17 00:00:00 2001 From: Matthew Hooker Date: Mon, 21 Nov 2016 15:35:57 -0800 Subject: [PATCH 4/4] Fix nested pp case --- fix/fixer_pp_manifest_filename.go | 39 ++++++++++++++++---------- fix/fixer_pp_manifest_filename_test.go | 20 ++++++++++--- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/fix/fixer_pp_manifest_filename.go b/fix/fixer_pp_manifest_filename.go index 923f63c93..50b3e5e16 100644 --- a/fix/fixer_pp_manifest_filename.go +++ b/fix/fixer_pp_manifest_filename.go @@ -1,7 +1,6 @@ package fix import ( - "fmt" "github.com/mitchellh/mapstructure" ) @@ -12,28 +11,40 @@ func (FixerManifestFilename) Fix(input map[string]interface{}) (map[string]inter // Our template type we'll use for this fixer only type template struct { - PostProcessors []map[string]interface{} `mapstructure:"post-processors"` + PostProcessors []interface{} `mapstructure:"post-processors"` } // Decode the input into our structure, if we can - fmt.Println("Got 0") var tpl template if err := mapstructure.Decode(input, &tpl); err != nil { - fmt.Println("Got 1") return nil, err } - for _, pp := range tpl.PostProcessors { - ppTypeRaw, ok := pp["type"] - if !ok { - continue + + // Go through each post-processor and get out all the complex configs + pps := make([]map[string]interface{}, 0, len(tpl.PostProcessors)) + for _, rawPP := range tpl.PostProcessors { + switch pp := rawPP.(type) { + case string: + case map[string]interface{}: + pps = append(pps, pp) + case []interface{}: + for _, innerRawPP := range pp { + if innerPP, ok := innerRawPP.(map[string]interface{}); ok { + pps = append(pps, innerPP) + } + } } + } - ppType, ok := ppTypeRaw.(string) + for _, pp := range pps { + ppTypeRaw, ok := pp["type"] if !ok { continue } - if ppType != "manifest" { + if ppType, ok := ppTypeRaw.(string); !ok { + continue + } else if ppType != "manifest" { continue } @@ -42,13 +53,11 @@ func (FixerManifestFilename) Fix(input map[string]interface{}) (map[string]inter continue } - filename, ok := filenameRaw.(string) - if !ok { - continue + if filename, ok := filenameRaw.(string); ok { + delete(pp, "filename") + pp["output"] = filename } - delete(pp, "filename") - pp["output"] = filename } input["post-processors"] = tpl.PostProcessors diff --git a/fix/fixer_pp_manifest_filename_test.go b/fix/fixer_pp_manifest_filename_test.go index ed726dfd6..907d41260 100644 --- a/fix/fixer_pp_manifest_filename_test.go +++ b/fix/fixer_pp_manifest_filename_test.go @@ -13,20 +13,32 @@ func TestFixerManifestPPFilename_Fix(t *testing.T) { var f FixerManifestFilename input := map[string]interface{}{ - "post-processors": []map[string]interface{}{ - { + "post-processors": []interface{}{ + map[string]interface{}{ "type": "manifest", "filename": "foo", }, + []interface{}{ + map[string]interface{}{ + "type": "manifest", + "filename": "foo", + }, + }, }, } expected := map[string]interface{}{ - "post-processors": []map[string]interface{}{ - { + "post-processors": []interface{}{ + map[string]interface{}{ "type": "manifest", "output": "foo", }, + []interface{}{ + map[string]interface{}{ + "type": "manifest", + "output": "foo", + }, + }, }, }