From 6762965696ee05789ad293628e8f2a2d2b8062f7 Mon Sep 17 00:00:00 2001 From: Orivej Desh Date: Wed, 14 Sep 2016 00:04:18 +0000 Subject: [PATCH] Add -on-error command line argument to allow preserving artifacts on builder errors Resolves #409 --- builder/amazon/chroot/builder.go | 10 +- builder/amazon/ebs/builder.go | 10 +- builder/amazon/instance/builder.go | 10 +- builder/azure/arm/builder.go | 15 +-- builder/digitalocean/builder.go | 10 +- builder/docker/builder.go | 10 +- builder/googlecompute/builder.go | 9 +- builder/null/builder.go | 10 +- builder/openstack/builder.go | 10 +- builder/parallels/iso/builder.go | 12 +-- builder/parallels/pvm/builder.go | 11 +-- builder/qemu/builder.go | 12 +-- builder/virtualbox/iso/builder.go | 12 +-- builder/virtualbox/ovf/builder.go | 11 +-- builder/vmware/iso/builder.go | 12 +-- builder/vmware/vmx/builder.go | 11 +-- command/build.go | 7 ++ common/multistep_runner.go | 148 +++++++++++++++++++++++++++++ common/packer_config.go | 1 + packer/build.go | 22 +++++ packer/build_test.go | 2 + packer/rpc/build.go | 14 ++- packer/rpc/build_test.go | 32 +++++-- 23 files changed, 231 insertions(+), 170 deletions(-) create mode 100644 common/multistep_runner.go diff --git a/builder/amazon/chroot/builder.go b/builder/amazon/chroot/builder.go index 5e6013a546e..dcfd7bc4168 100644 --- a/builder/amazon/chroot/builder.go +++ b/builder/amazon/chroot/builder.go @@ -262,15 +262,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ) // Run! - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // If there was an error, return that diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index 7174d6b8e0e..9916d821d56 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -179,15 +179,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run! - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // If there was an error, return that diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 96b8fa9cc81..a900aef9b2d 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -262,15 +262,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run! - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // If there was an error, return that diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go index db344acb33c..30029be52aa 100644 --- a/builder/azure/arm/builder.go +++ b/builder/azure/arm/builder.go @@ -157,7 +157,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ui.Message(fmt.Sprintf("temp admin password: '%s'", b.config.Password)) } - b.runner = b.createRunner(&steps, ui) + b.runner = packerCommon.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(b.stateBag) // Report any errors. @@ -198,19 +198,6 @@ func (b *Builder) Cancel() { } } -func (b *Builder) createRunner(steps *[]multistep.Step, ui packer.Ui) multistep.Runner { - if b.config.PackerDebug { - return &multistep.DebugRunner{ - Steps: *steps, - PauseFn: packerCommon.MultistepDebugFn(ui), - } - } - - return &multistep.BasicRunner{ - Steps: *steps, - } -} - func (b *Builder) getBlobEndpoint(client *AzureClient, resourceGroupName string, storageAccountName string) (string, error) { account, err := client.AccountsClient.GetProperties(resourceGroupName, storageAccountName) if err != nil { diff --git a/builder/digitalocean/builder.go b/builder/digitalocean/builder.go index 0c2cf968601..bafad752277 100644 --- a/builder/digitalocean/builder.go +++ b/builder/digitalocean/builder.go @@ -73,15 +73,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run the steps - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // If there was an error, return that diff --git a/builder/docker/builder.go b/builder/docker/builder.go index cfc5bf423f1..8e7e2cf190c 100644 --- a/builder/docker/builder.go +++ b/builder/docker/builder.go @@ -78,15 +78,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("driver", driver) // Run! - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // If there was an error, return that diff --git a/builder/googlecompute/builder.go b/builder/googlecompute/builder.go index d1c7336294f..014c40a38ed 100644 --- a/builder/googlecompute/builder.go +++ b/builder/googlecompute/builder.go @@ -73,14 +73,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run the steps. - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // Report any errors. diff --git a/builder/null/builder.go b/builder/null/builder.go index 949c01c2b2f..cce9227d6d3 100644 --- a/builder/null/builder.go +++ b/builder/null/builder.go @@ -46,15 +46,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) // Run! - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // If there was an error, return that diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index d83086182d2..2e7f00e7ff1 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -116,15 +116,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run! - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) // If there was an error, return that diff --git a/builder/parallels/iso/builder.go b/builder/parallels/iso/builder.go index 134f980f38b..359a439b5b1 100644 --- a/builder/parallels/iso/builder.go +++ b/builder/parallels/iso/builder.go @@ -215,17 +215,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) // Run - if b.config.PackerDebug { - pauseFn := common.MultistepDebugFn(ui) - state.Put("pauseFn", pauseFn) - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: pauseFn, - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // If there was an error, return that diff --git a/builder/parallels/pvm/builder.go b/builder/parallels/pvm/builder.go index b62181b0607..45aed55bf5f 100644 --- a/builder/parallels/pvm/builder.go +++ b/builder/parallels/pvm/builder.go @@ -108,16 +108,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run the steps. - if b.config.PackerDebug { - pauseFn := common.MultistepDebugFn(ui) - state.Put("pauseFn", pauseFn) - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: pauseFn, - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // Report any errors. diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index 7b9630b76c4..82bff8d74dc 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -422,17 +422,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) // Run - if b.config.PackerDebug { - pauseFn := common.MultistepDebugFn(ui) - state.Put("pauseFn", pauseFn) - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: pauseFn, - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // If there was an error, return that diff --git a/builder/virtualbox/iso/builder.go b/builder/virtualbox/iso/builder.go index 0d0790ea165..a69ad83eac2 100644 --- a/builder/virtualbox/iso/builder.go +++ b/builder/virtualbox/iso/builder.go @@ -275,17 +275,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) // Run - if b.config.PackerDebug { - pauseFn := common.MultistepDebugFn(ui) - state.Put("pauseFn", pauseFn) - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: pauseFn, - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // If there was an error, return that diff --git a/builder/virtualbox/ovf/builder.go b/builder/virtualbox/ovf/builder.go index 502f667347e..56e349b8304 100644 --- a/builder/virtualbox/ovf/builder.go +++ b/builder/virtualbox/ovf/builder.go @@ -135,16 +135,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run the steps. - if b.config.PackerDebug { - pauseFn := common.MultistepDebugFn(ui) - state.Put("pauseFn", pauseFn) - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: pauseFn, - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // Report any errors. diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index 5a6495cb212..4d43b36853e 100755 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -305,17 +305,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run! - if b.config.PackerDebug { - pauseFn := common.MultistepDebugFn(ui) - state.Put("pauseFn", pauseFn) - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: pauseFn, - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // If there was an error, return that diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index d82f03f1c96..cf2df99ea3d 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -122,16 +122,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run the steps. - if b.config.PackerDebug { - pauseFn := common.MultistepDebugFn(ui) - state.Put("pauseFn", pauseFn) - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: pauseFn, - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // Report any errors. diff --git a/command/build.go b/command/build.go index 5d683d4b008..7cbc6bed260 100644 --- a/command/build.go +++ b/command/build.go @@ -20,11 +20,13 @@ type BuildCommand struct { func (c BuildCommand) Run(args []string) int { var cfgColor, cfgDebug, cfgForce, cfgParallel bool + var cfgOnError string flags := c.Meta.FlagSet("build", FlagSetBuildFilter|FlagSetVars) flags.Usage = func() { c.Ui.Say(c.Help()) } flags.BoolVar(&cfgColor, "color", true, "") flags.BoolVar(&cfgDebug, "debug", false, "") flags.BoolVar(&cfgForce, "force", false, "") + flags.StringVar(&cfgOnError, "on-error", "cleanup", "") flags.BoolVar(&cfgParallel, "parallel", true, "") if err := flags.Parse(args); err != nil { return 1 @@ -99,12 +101,14 @@ func (c BuildCommand) Run(args []string) int { log.Printf("Build debug mode: %v", cfgDebug) log.Printf("Force build: %v", cfgForce) + log.Printf("On error: %v", cfgOnError) // Set the debug and force mode and prepare all the builds for _, b := range builds { log.Printf("Preparing build: %s", b.Name()) b.SetDebug(cfgDebug) b.SetForce(cfgForce) + b.SetOnError(cfgOnError) warnings, err := b.Prepare() if err != nil { @@ -284,6 +288,9 @@ Options: -except=foo,bar,baz Build all builds other than these -force Force a build to continue if artifacts exist, deletes existing artifacts -machine-readable Machine-readable output + -on-error=abort When a builder fails, abort without cleanup + -on-error=ask When a builder fails, prompt for action + -on-error=cleanup When a builder fails, clean up and exit (the default) -only=foo,bar,baz Only build the given builds by name -parallel=false Disable parallelization (on by default) -var 'key=value' Variable for templates, can be used multiple times. diff --git a/common/multistep_runner.go b/common/multistep_runner.go new file mode 100644 index 00000000000..7dda2bbd08a --- /dev/null +++ b/common/multistep_runner.go @@ -0,0 +1,148 @@ +package common + +import ( + "fmt" + "log" + "os" + "reflect" + "time" + + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" +) + +func newRunner(steps []multistep.Step, config PackerConfig, ui packer.Ui) (multistep.Runner, interface{}) { + switch config.PackerOnError { + case "cleanup", "": + case "abort": + for i, step := range steps { + steps[i] = abortStep{step, ui} + } + case "ask": + for i, step := range steps { + steps[i] = askStep{step, ui} + } + default: + ui.Error(fmt.Sprintf("Ignoring unknown on-error value %q", config.PackerOnError)) + } + + if config.PackerDebug { + pauseFn := MultistepDebugFn(ui) + return &multistep.DebugRunner{Steps: steps, PauseFn: pauseFn}, pauseFn + } else { + return &multistep.BasicRunner{Steps: steps}, nil + } +} + +func NewRunner(steps []multistep.Step, config PackerConfig, ui packer.Ui) multistep.Runner { + runner, _ := newRunner(steps, config, ui) + return runner +} + +func NewRunnerWithPauseFn(steps []multistep.Step, config PackerConfig, ui packer.Ui, state multistep.StateBag) multistep.Runner { + runner, pauseFn := newRunner(steps, config, ui) + if pauseFn != nil { + state.Put("pauseFn", pauseFn) + } + return runner +} + +func typeName(i interface{}) string { + return reflect.Indirect(reflect.ValueOf(i)).Type().Name() +} + +type abortStep struct { + step multistep.Step + ui packer.Ui +} + +func (s abortStep) Run(state multistep.StateBag) multistep.StepAction { + return s.step.Run(state) +} + +func (s abortStep) Cleanup(state multistep.StateBag) { + if _, ok := state.GetOk(multistep.StateCancelled); ok { + s.ui.Error("Interrupted, aborting...") + os.Exit(1) + } + if _, ok := state.GetOk(multistep.StateHalted); ok { + s.ui.Error(fmt.Sprintf("Step %q failed, aborting...", typeName(s.step))) + os.Exit(1) + } + s.step.Cleanup(state) +} + +type askStep struct { + step multistep.Step + ui packer.Ui +} + +func (s askStep) Run(state multistep.StateBag) (action multistep.StepAction) { + for { + action = s.step.Run(state) + + if action != multistep.ActionHalt { + return + } + + switch ask(s.ui, typeName(s.step), state) { + case askCleanup: + return + case askAbort: + os.Exit(1) + case askRetry: + continue + } + } +} + +func (s askStep) Cleanup(state multistep.StateBag) { + s.step.Cleanup(state) +} + +type askResponse int + +const ( + askCleanup askResponse = iota + askAbort + askRetry +) + +func ask(ui packer.Ui, name string, state multistep.StateBag) askResponse { + ui.Say(fmt.Sprintf("Step %q failed", name)) + + result := make(chan askResponse) + go func() { + result <- askPrompt(ui) + }() + + for { + select { + case response := <-result: + return response + case <-time.After(100 * time.Millisecond): + if _, ok := state.GetOk(multistep.StateCancelled); ok { + return askCleanup + } + } + } +} + +func askPrompt(ui packer.Ui) askResponse { + for { + line, err := ui.Ask("[C]lean up and exit, [A]bort without cleanup, or [R]etry step (build may fail even if retry succeeds)? [car]") + if err != nil { + log.Printf("Error asking for input: %s", err) + } + + switch { + case len(line) == 0 || line[0] == 'c': + return askCleanup + case line[0] == 'a': + return askAbort + case line[0] == 'r': + return askRetry + } + ui.Say(fmt.Sprintf("Incorrect input: %#v", line)) + } +} diff --git a/common/packer_config.go b/common/packer_config.go index 2ef86e58243..3a14f64b512 100644 --- a/common/packer_config.go +++ b/common/packer_config.go @@ -8,5 +8,6 @@ type PackerConfig struct { PackerBuilderType string `mapstructure:"packer_builder_type"` PackerDebug bool `mapstructure:"packer_debug"` PackerForce bool `mapstructure:"packer_force"` + PackerOnError string `mapstructure:"packer_on_error"` PackerUserVars map[string]string `mapstructure:"packer_user_variables"` } diff --git a/packer/build.go b/packer/build.go index 757ef89eb4a..bd3c2acbc47 100644 --- a/packer/build.go +++ b/packer/build.go @@ -24,6 +24,12 @@ const ( // force build is enabled. ForceConfigKey = "packer_force" + // This key determines what to do when a normal multistep step fails + // - "cleanup" - run cleanup steps + // - "abort" - exit without cleanup + // - "ask" - ask the user + OnErrorConfigKey = "packer_on_error" + // TemplatePathKey is the path to the template that configured this build TemplatePathKey = "packer_template_path" @@ -67,6 +73,12 @@ type Build interface { // When SetForce is set to true, existing artifacts from the build are // deleted prior to the build. SetForce(bool) + + // SetOnError will determines what to do when a normal multistep step fails + // - "cleanup" - run cleanup steps + // - "abort" - exit without cleanup + // - "ask" - ask the user + SetOnError(string) } // A build struct represents a single build job, the result of which should @@ -86,6 +98,7 @@ type coreBuild struct { debug bool force bool + onError string l sync.Mutex prepareCalled bool } @@ -129,6 +142,7 @@ func (b *coreBuild) Prepare() (warn []string, err error) { BuilderTypeConfigKey: b.builderType, DebugConfigKey: b.debug, ForceConfigKey: b.force, + OnErrorConfigKey: b.onError, TemplatePathKey: b.templatePath, UserVariablesConfigKey: b.variables, } @@ -306,6 +320,14 @@ func (b *coreBuild) SetForce(val bool) { b.force = val } +func (b *coreBuild) SetOnError(val string) { + if b.prepareCalled { + panic("prepare has already been called") + } + + b.onError = val +} + // Cancels the build if it is running. func (b *coreBuild) Cancel() { b.builder.Cancel() diff --git a/packer/build_test.go b/packer/build_test.go index e2931897298..804ecbaf406 100644 --- a/packer/build_test.go +++ b/packer/build_test.go @@ -23,6 +23,7 @@ func testBuild() *coreBuild { }, }, variables: make(map[string]string), + onError: "cleanup", } } @@ -32,6 +33,7 @@ func testDefaultPackerConfig() map[string]interface{} { BuilderTypeConfigKey: "foo", DebugConfigKey: false, ForceConfigKey: false, + OnErrorConfigKey: "cleanup", TemplatePathKey: "", UserVariablesConfigKey: make(map[string]string), } diff --git a/packer/rpc/build.go b/packer/rpc/build.go index 4d0b7edf4d9..7a99a54a4ca 100644 --- a/packer/rpc/build.go +++ b/packer/rpc/build.go @@ -1,8 +1,9 @@ package rpc import ( - "github.com/mitchellh/packer/packer" "net/rpc" + + "github.com/mitchellh/packer/packer" ) // An implementation of packer.Build where the build is actually executed @@ -79,6 +80,12 @@ func (b *build) SetForce(val bool) { } } +func (b *build) SetOnError(val string) { + if err := b.client.Call("Build.SetOnError", val, new(interface{})); err != nil { + panic(err) + } +} + func (b *build) Cancel() { if err := b.client.Call("Build.Cancel", new(interface{}), new(interface{})); err != nil { panic(err) @@ -134,6 +141,11 @@ func (b *BuildServer) SetForce(val *bool, reply *interface{}) error { return nil } +func (b *BuildServer) SetOnError(val *string, reply *interface{}) error { + b.build.SetOnError(*val) + return nil +} + func (b *BuildServer) Cancel(args *interface{}, reply *interface{}) error { b.build.Cancel() return nil diff --git a/packer/rpc/build_test.go b/packer/rpc/build_test.go index d2f058e7dd1..57a4b8dc283 100644 --- a/packer/rpc/build_test.go +++ b/packer/rpc/build_test.go @@ -2,23 +2,25 @@ package rpc import ( "errors" - "github.com/mitchellh/packer/packer" "reflect" "testing" + + "github.com/mitchellh/packer/packer" ) var testBuildArtifact = &packer.MockArtifact{} type testBuild struct { - nameCalled bool - prepareCalled bool - prepareWarnings []string - runCalled bool - runCache packer.Cache - runUi packer.Ui - setDebugCalled bool - setForceCalled bool - cancelCalled bool + nameCalled bool + prepareCalled bool + prepareWarnings []string + runCalled bool + runCache packer.Cache + runUi packer.Ui + setDebugCalled bool + setForceCalled bool + setOnErrorCalled bool + cancelCalled bool errRunResult bool } @@ -53,6 +55,10 @@ func (b *testBuild) SetForce(bool) { b.setForceCalled = true } +func (b *testBuild) SetOnError(string) { + b.setOnErrorCalled = true +} + func (b *testBuild) Cancel() { b.cancelCalled = true } @@ -116,6 +122,12 @@ func TestBuild(t *testing.T) { t.Fatal("should be called") } + // Test SetOnError + bClient.SetOnError("ask") + if !b.setOnErrorCalled { + t.Fatal("should be called") + } + // Test Cancel bClient.Cancel() if !b.cancelCalled {