diff --git a/builder/googlecompute/driver.go b/builder/googlecompute/driver.go index 88551c149..4a0f20448 100644 --- a/builder/googlecompute/driver.go +++ b/builder/googlecompute/driver.go @@ -4,6 +4,9 @@ package googlecompute // with GCE. The Driver interface exists mostly to allow a mock implementation // to be used to test the steps. type Driver interface { + // DeleteInstance deletes the given instance. + DeleteInstance(zone, name string) (<-chan error, error) + // RunInstance takes the given config and launches an instance. RunInstance(*InstanceConfig) (<-chan error, error) } diff --git a/builder/googlecompute/driver_gce.go b/builder/googlecompute/driver_gce.go index 38d68c9b7..9cdfb45f5 100644 --- a/builder/googlecompute/driver_gce.go +++ b/builder/googlecompute/driver_gce.go @@ -59,6 +59,17 @@ func NewDriverGCE(ui packer.Ui, projectId string, c *clientSecrets, key []byte) }, nil } +func (d *driverGCE) DeleteInstance(zone, name string) (<-chan error, error) { + op, err := d.service.Instances.Delete(d.projectId, zone, name).Do() + if err != nil { + return nil, err + } + + errCh := make(chan error, 1) + go waitForState(errCh, "DONE", d.refreshZoneOp(zone, op)) + return errCh, nil +} + func (d *driverGCE) RunInstance(c *InstanceConfig) (<-chan error, error) { // Get the zone d.ui.Message(fmt.Sprintf("Loading zone: %s", c.Zone)) diff --git a/builder/googlecompute/driver_mock.go b/builder/googlecompute/driver_mock.go index 4293e8787..6a0e6821a 100644 --- a/builder/googlecompute/driver_mock.go +++ b/builder/googlecompute/driver_mock.go @@ -3,11 +3,30 @@ package googlecompute // DriverMock is a Driver implementation that is a mocked out so that // it can be used for tests. type DriverMock struct { + DeleteInstanceZone string + DeleteInstanceName string + DeleteInstanceErrCh <-chan error + DeleteInstanceErr error + RunInstanceConfig *InstanceConfig RunInstanceErrCh <-chan error RunInstanceErr error } +func (d *DriverMock) DeleteInstance(zone, name string) (<-chan error, error) { + d.DeleteInstanceZone = zone + d.DeleteInstanceName = name + + resultCh := d.DeleteInstanceErrCh + if resultCh == nil { + ch := make(chan error) + close(ch) + resultCh = ch + } + + return resultCh, d.DeleteInstanceErr +} + func (d *DriverMock) RunInstance(c *InstanceConfig) (<-chan error, error) { d.RunInstanceConfig = c diff --git a/builder/googlecompute/step_create_instance.go b/builder/googlecompute/step_create_instance.go index eb6f3f0bf..dcc8e88f7 100644 --- a/builder/googlecompute/step_create_instance.go +++ b/builder/googlecompute/step_create_instance.go @@ -68,27 +68,28 @@ func (s *StepCreateInstance) Cleanup(state multistep.StateBag) { if s.instanceName == "" { return } - /* - var ( - client = state.Get("client").(*GoogleComputeClient) - config = state.Get("config").(*Config) - ui = state.Get("ui").(packer.Ui) - ) - ui.Say("Destroying instance...") - operation, err := client.DeleteInstance(config.Zone, s.instanceName) - if err != nil { - ui.Error(fmt.Sprintf("Error destroying instance. Please destroy it manually: %v", s.instanceName)) + + config := state.Get("config").(*Config) + driver := state.Get("driver").(Driver) + ui := state.Get("ui").(packer.Ui) + + ui.Say("Deleting instance...") + errCh, err := driver.DeleteInstance(config.Zone, s.instanceName) + if err == nil { + select { + case err = <-errCh: + case <-time.After(config.stateTimeout): + err = errors.New("time out while waiting for instance to delete") } - ui.Say("Waiting for the instance to be deleted...") - for { - status, err := client.ZoneOperationStatus(config.Zone, operation.Name) - if err != nil { - ui.Error(fmt.Sprintf("Error destroying instance. Please destroy it manually: %v", s.instanceName)) - } - if status == "DONE" { - break - } - } - */ + } + + if err != nil { + ui.Error(fmt.Sprintf( + "Error deleting instance. Please delete it manually.\n\n"+ + "Name: %s\n"+ + "Error: %s", s.instanceName, err)) + } + + s.instanceName = "" return } diff --git a/builder/googlecompute/step_create_instance_test.go b/builder/googlecompute/step_create_instance_test.go index 703fefde1..c7272bea8 100644 --- a/builder/googlecompute/step_create_instance_test.go +++ b/builder/googlecompute/step_create_instance_test.go @@ -18,15 +18,29 @@ func TestStepCreateInstance(t *testing.T) { state.Put("ssh_public_key", "key") + config := state.Get("config").(*Config) + driver := state.Get("driver").(*DriverMock) + // run the step if action := step.Run(state); action != multistep.ActionContinue { t.Fatalf("bad action: %#v", action) } // Verify state - if _, ok := state.GetOk("instance_name"); !ok { + nameRaw, ok := state.GetOk("instance_name") + if !ok { t.Fatal("should have instance name") } + + // cleanup + step.Cleanup(state) + + if driver.DeleteInstanceName != nameRaw.(string) { + t.Fatal("should've deleted instance") + } + if driver.DeleteInstanceZone != config.Zone { + t.Fatal("bad zone: %#v", driver.DeleteInstanceZone) + } } func TestStepCreateInstance_error(t *testing.T) {