From ba25e68fe0fdb6de12d44f26e8908890734a0591 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 29 Nov 2018 14:32:52 -0800 Subject: [PATCH 1/5] add a new breakpoint provisioner --- command/plugin.go | 2 + provisioner/breakpoint/provisioner.go | 73 +++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 provisioner/breakpoint/provisioner.go diff --git a/command/plugin.go b/command/plugin.go index 71db5843e..d0cd68153 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -65,6 +65,7 @@ import ( vspheretemplatepostprocessor "github.com/hashicorp/packer/post-processor/vsphere-template" ansibleprovisioner "github.com/hashicorp/packer/provisioner/ansible" ansiblelocalprovisioner "github.com/hashicorp/packer/provisioner/ansible-local" + breakpointprovisioner "github.com/hashicorp/packer/provisioner/breakpoint" chefclientprovisioner "github.com/hashicorp/packer/provisioner/chef-client" chefsoloprovisioner "github.com/hashicorp/packer/provisioner/chef-solo" convergeprovisioner "github.com/hashicorp/packer/provisioner/converge" @@ -122,6 +123,7 @@ var Builders = map[string]packer.Builder{ var Provisioners = map[string]packer.Provisioner{ "ansible": new(ansibleprovisioner.Provisioner), "ansible-local": new(ansiblelocalprovisioner.Provisioner), + "breakpoint": new(breakpointprovisioner.Provisioner), "chef-client": new(chefclientprovisioner.Provisioner), "chef-solo": new(chefsoloprovisioner.Provisioner), "converge": new(convergeprovisioner.Provisioner), diff --git a/provisioner/breakpoint/provisioner.go b/provisioner/breakpoint/provisioner.go new file mode 100644 index 000000000..05428383d --- /dev/null +++ b/provisioner/breakpoint/provisioner.go @@ -0,0 +1,73 @@ +package breakpoint + +import ( + "fmt" + "log" + "os" + + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/helper/config" + "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/template/interpolate" +) + +type Config struct { + common.PackerConfig `mapstructure:",squash"` + + // The local path of the file to upload. + Note string `mapstructure:"note"` + + ctx interpolate.Context +} + +type Provisioner struct { + config Config +} + +func (p *Provisioner) Prepare(raws ...interface{}) error { + err := config.Decode(&p.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateContext: &p.config.ctx, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{}, + }, + }, raws...) + if err != nil { + return err + } + + return nil +} + +func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { + if p.config.Note != "" { + ui.Say(fmt.Sprintf("Pausing at breakpoint provisioner with note \"%s\".", p.config.Note)) + } else { + ui.Say("Pausing at breakpoint provisioner.") + } + + message := fmt.Sprintf( + "Press enter to continue.") + + result := make(chan string, 1) + go func() { + line, err := ui.Ask(message) + if err != nil { + log.Printf("Error asking for input: %s", err) + } + + result <- line + }() + + select { + case <-result: + return nil + } + + return nil +} + +func (p *Provisioner) Cancel() { + // Just hard quit. + os.Exit(0) +} From 1aeb29036aa0617052a688f06fecc8361ba9102b Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 29 Nov 2018 14:47:06 -0800 Subject: [PATCH 2/5] docs --- .../docs/provisioners/breakpoint.html.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 website/source/docs/provisioners/breakpoint.html.md diff --git a/website/source/docs/provisioners/breakpoint.html.md b/website/source/docs/provisioners/breakpoint.html.md new file mode 100644 index 000000000..536768edb --- /dev/null +++ b/website/source/docs/provisioners/breakpoint.html.md @@ -0,0 +1,37 @@ +--- +description: | + The breakpoint provisioner will pause until the user presses "enter" to + resume the build. This is intended for debugging purposes, and allows you + to halt at a particular part of the provisioning process. +layout: docs +page_title: 'breakpoint - Provisioners' +sidebar_current: 'docs-provisioners-breakpoint' +--- + +# File Provisioner + +Type: `breakpoint` + +The breakpoint provisioner will pause until the user presses "enter" to +resume the build. This is intended for debugging purposes, and allows you +to halt at a particular part of the provisioning process, rather than using the +`-debug` flag, which will instead halt at every step and between every +provisioner. + +## Basic Example + +``` json +{ + "type": "breakpoint", + "note": "foo bar baz" +} +``` + +## Configuration Reference + +### Optional + +- `note` (string) - a string to include explaining the purpose or location of + the breakpoint. For example, you may find it useful to number your + breakpoints or label them with information about where in the build they + occur \ No newline at end of file From a93721c54df8e0309af17fc6fb007a8e89e584d5 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 29 Nov 2018 15:09:14 -0800 Subject: [PATCH 3/5] add disable option to breakpoint provisioner --- provisioner/breakpoint/provisioner.go | 15 ++++++++-- .../docs/provisioners/breakpoint.html.md | 30 +++++++++++++++---- website/source/layouts/docs.erb | 3 ++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/provisioner/breakpoint/provisioner.go b/provisioner/breakpoint/provisioner.go index 05428383d..4f213f7dd 100644 --- a/provisioner/breakpoint/provisioner.go +++ b/provisioner/breakpoint/provisioner.go @@ -14,8 +14,8 @@ import ( type Config struct { common.PackerConfig `mapstructure:",squash"` - // The local path of the file to upload. - Note string `mapstructure:"note"` + Note string `mapstructure:"note"` + Disable bool `mapstructure:"disable"` ctx interpolate.Context } @@ -40,6 +40,17 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { + if p.config.Disable { + if p.config.Note != "" { + ui.Say(fmt.Sprintf( + "Breakpoint provisioner with note \"%s\" disabled; continuing...", + p.config.Note)) + } else { + ui.Say("Breakpoint provisioner disabled; continuing...") + } + + return nil + } if p.config.Note != "" { ui.Say(fmt.Sprintf("Pausing at breakpoint provisioner with note \"%s\".", p.config.Note)) } else { diff --git a/website/source/docs/provisioners/breakpoint.html.md b/website/source/docs/provisioners/breakpoint.html.md index 536768edb..edcc48405 100644 --- a/website/source/docs/provisioners/breakpoint.html.md +++ b/website/source/docs/provisioners/breakpoint.html.md @@ -8,15 +8,16 @@ page_title: 'breakpoint - Provisioners' sidebar_current: 'docs-provisioners-breakpoint' --- -# File Provisioner +# Breakpoint Provisioner Type: `breakpoint` The breakpoint provisioner will pause until the user presses "enter" to resume the build. This is intended for debugging purposes, and allows you -to halt at a particular part of the provisioning process, rather than using the -`-debug` flag, which will instead halt at every step and between every -provisioner. +to halt at a particular part of the provisioning process. + +This is independent of the `-debug` flag, which will instead halt at every step +and between every provisioner. ## Basic Example @@ -31,7 +32,26 @@ provisioner. ### Optional +- `disable` (boolean) - If `true`, skip the breakpoint. Useful for when you + have set multiple breakpoints and want to toggle them off or on. + Default: `false` + - `note` (string) - a string to include explaining the purpose or location of the breakpoint. For example, you may find it useful to number your breakpoints or label them with information about where in the build they - occur \ No newline at end of file + occur + +## Usage + +Insert this provisioner wherever you want the build to pause. You'll see ui +output prompting you to press "enter" to continue the build when you are ready. + +For example: + +``` +==> docker: Pausing at breakpoint provisioner with note "foo bar baz". +==> docker: Press enter to continue. +``` + +Once you press enter, the build will resume and run normally until it either +completes or errors. \ No newline at end of file diff --git a/website/source/layouts/docs.erb b/website/source/layouts/docs.erb index eb400223b..5a9f4436d 100644 --- a/website/source/layouts/docs.erb +++ b/website/source/layouts/docs.erb @@ -201,6 +201,9 @@ > Ansible Remote + > + Breakpoint + > Chef Client From e6477d13fbc9832c22d52dd024a1984cd6f0e531 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 29 Nov 2018 15:22:26 -0800 Subject: [PATCH 4/5] fix empty return --- provisioner/breakpoint/provisioner.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/provisioner/breakpoint/provisioner.go b/provisioner/breakpoint/provisioner.go index 4f213f7dd..c1a270381 100644 --- a/provisioner/breakpoint/provisioner.go +++ b/provisioner/breakpoint/provisioner.go @@ -74,8 +74,6 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { case <-result: return nil } - - return nil } func (p *Provisioner) Cancel() { From 8a7ec456f146ef5b88d984701c6000bca98b3687 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Fri, 30 Nov 2018 10:46:40 -0800 Subject: [PATCH 5/5] use error groups so we can return errors --- provisioner/breakpoint/provisioner.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/provisioner/breakpoint/provisioner.go b/provisioner/breakpoint/provisioner.go index c1a270381..b64f97759 100644 --- a/provisioner/breakpoint/provisioner.go +++ b/provisioner/breakpoint/provisioner.go @@ -2,9 +2,10 @@ package breakpoint import ( "fmt" - "log" "os" + "golang.org/x/sync/errgroup" + "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/packer" @@ -60,20 +61,22 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { message := fmt.Sprintf( "Press enter to continue.") + var g errgroup.Group result := make(chan string, 1) - go func() { + g.Go(func() error { line, err := ui.Ask(message) if err != nil { - log.Printf("Error asking for input: %s", err) + return fmt.Errorf("Error asking for input: %s", err) } result <- line - }() - - select { - case <-result: return nil + }) + + if err := g.Wait(); err != nil { + return err } + return nil } func (p *Provisioner) Cancel() {