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..b64f97759 --- /dev/null +++ b/provisioner/breakpoint/provisioner.go @@ -0,0 +1,85 @@ +package breakpoint + +import ( + "fmt" + "os" + + "golang.org/x/sync/errgroup" + + "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"` + + Note string `mapstructure:"note"` + Disable bool `mapstructure:"disable"` + + 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.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 { + ui.Say("Pausing at breakpoint provisioner.") + } + + message := fmt.Sprintf( + "Press enter to continue.") + + var g errgroup.Group + result := make(chan string, 1) + g.Go(func() error { + line, err := ui.Ask(message) + if err != nil { + return fmt.Errorf("Error asking for input: %s", err) + } + + result <- line + return nil + }) + + if err := g.Wait(); err != nil { + return err + } + return nil +} + +func (p *Provisioner) Cancel() { + // Just hard quit. + os.Exit(0) +} diff --git a/website/source/docs/provisioners/breakpoint.html.md b/website/source/docs/provisioners/breakpoint.html.md new file mode 100644 index 000000000..edcc48405 --- /dev/null +++ b/website/source/docs/provisioners/breakpoint.html.md @@ -0,0 +1,57 @@ +--- +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' +--- + +# 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. + +This is independent of 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 + +- `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 + +## 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 @@