diff --git a/command/build.go b/command/build.go index 3eda31e91..8271f2ebb 100644 --- a/command/build.go +++ b/command/build.go @@ -361,7 +361,7 @@ Options: -only=foo,bar,baz Build only the specified builds. -force Force a build to continue if artifacts exist, deletes existing artifacts. -machine-readable Produce machine-readable output. - -on-error=[cleanup|abort|ask] If the build fails do: clean up (default), abort, or ask. + -on-error=[cleanup|abort|ask|run-cleanup-provisioner] If the build fails do: clean up (default), abort, ask, or run-cleanup-provisioner. -parallel-builds=1 Number of builds to run in parallel. 1 disables parallelization. 0 means no limit (Default: 0) -timestamp-ui Enable prefixing of each ui output with an RFC3339 timestamp. -var 'key=value' Variable for templates, can be used multiple times. diff --git a/command/cli.go b/command/cli.go index 4393624a6..0a5ebbad4 100644 --- a/command/cli.go +++ b/command/cli.go @@ -79,7 +79,7 @@ func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { flags.Int64Var(&ba.ParallelBuilds, "parallel-builds", 0, "") - flagOnError := enumflag.New(&ba.OnError, "cleanup", "abort", "ask") + flagOnError := enumflag.New(&ba.OnError, "cleanup", "abort", "ask", "run-cleanup-provisioner") flags.Var(flagOnError, "on-error", "") ba.MetaArgs.AddFlagSets(flags) diff --git a/common/multistep_runner.go b/common/multistep_runner.go index b93159fc2..7dd614562 100644 --- a/common/multistep_runner.go +++ b/common/multistep_runner.go @@ -17,12 +17,24 @@ func newRunner(steps []multistep.Step, config PackerConfig, ui packer.Ui) (multi case "", "cleanup": case "abort": for i, step := range steps { - steps[i] = abortStep{step, ui} + steps[i] = abortStep{ + step: step, + cleanupProv: false, + ui: ui, + } } case "ask": for i, step := range steps { steps[i] = askStep{step, ui} } + case "run-cleanup-provisioner": + for i, step := range steps { + steps[i] = abortStep{ + step: step, + cleanupProv: true, + ui: ui, + } + } } if config.PackerDebug { @@ -57,8 +69,9 @@ func typeName(i interface{}) string { } type abortStep struct { - step multistep.Step - ui packer.Ui + step multistep.Step + cleanupProv bool + ui packer.Ui } func (s abortStep) InnerStepName() string { @@ -70,6 +83,11 @@ func (s abortStep) Run(ctx context.Context, state multistep.StateBag) multistep. } func (s abortStep) Cleanup(state multistep.StateBag) { + if s.InnerStepName() == typeName(StepProvision{}) && s.cleanupProv { + s.step.Cleanup(state) + return + } + shouldCleanup := handleAbortsAndInterupts(state, s.ui, typeName(s.step)) if !shouldCleanup { return diff --git a/website/pages/docs/commands/build.mdx b/website/pages/docs/commands/build.mdx index 40cc1309f..02da4c497 100644 --- a/website/pages/docs/commands/build.mdx +++ b/website/pages/docs/commands/build.mdx @@ -40,12 +40,14 @@ artifacts that are created will be outputted at the end of the build. remove the artifacts from the previous build. This will allow the user to repeat a build without having to manually clean these artifacts beforehand. -- `-on-error=cleanup` (default), `-on-error=abort`, `-on-error=ask` - Selects - what to do when the build fails. `cleanup` cleans up after the previous - steps, deleting temporary files and virtual machines. `abort` exits without - any cleanup, which might require the next build to use `-force`. `ask` - presents a prompt and waits for you to decide to clean up, abort, or retry +- `-on-error=cleanup` (default), `-on-error=abort`, `-on-error=ask`, `-on-error=run-cleanup-provisioner` - + Selects what to do when the build fails. + - `cleanup` cleans up after the previous steps, deleting temporary files and virtual machines. + - `abort` exits without any cleanup, which might require the next build to use `-force`. + - `ask` presents a prompt and waits for you to decide to clean up, abort, or retry the failed step. + - `run-cleanup-provisioner` aborts and exits without any cleanup besides + the [error-cleanup-provisioner](/docs/templates/provisioners#on-error-provisioner) if one is defined. - `-only=foo,bar,baz` - Only run the builds with the given comma-separated names. Build names by default are their type, unless a specific `name`