From 2b9dd6854249390e3f92e66459e3d356302367ad Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Sun, 31 May 2015 23:57:23 +0200 Subject: [PATCH 1/2] Handle possible error in WaitForSpecific func In some situations we need to be aware of errors to basically return it rather than polling again and angain until the timeout. Signed-off-by: Guillaume Giamarchi --- utils/utils.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index d2d0483b..e2ec725d 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -94,9 +94,13 @@ func CopyFile(src, dst string) error { return nil } -func WaitForSpecific(f func() bool, maxAttempts int, waitInterval time.Duration) error { +func WaitForSpecificOrError(f func() (bool, error), maxAttempts int, waitInterval time.Duration) error { for i := 0; i < maxAttempts; i++ { - if f() { + stop, err := f() + if err != nil { + return err + } + if stop { return nil } time.Sleep(waitInterval) @@ -104,6 +108,12 @@ func WaitForSpecific(f func() bool, maxAttempts int, waitInterval time.Duration) return fmt.Errorf("Maximum number of retries (%d) exceeded", maxAttempts) } +func WaitForSpecific(f func() bool, maxAttempts int, waitInterval time.Duration) error { + return WaitForSpecificOrError(func() (bool, error) { + return f(), nil + }, maxAttempts, waitInterval) +} + func WaitFor(f func() bool) error { return WaitForSpecific(f, 60, 3*time.Second) } From de817cfe46b56424afa0d80155bb5be4c47d5fa0 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Mon, 1 Jun 2015 00:41:41 +0200 Subject: [PATCH 2/2] Stop polling the instance when status is ERROR Fix #1269 Signed-off-by: Guillaume Giamarchi --- drivers/openstack/client.go | 26 ++++++++++++++++++++------ drivers/openstack/openstack.go | 2 +- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/openstack/client.go b/drivers/openstack/client.go index e464a567..218af191 100644 --- a/drivers/openstack/client.go +++ b/drivers/openstack/client.go @@ -4,8 +4,10 @@ import ( "crypto/tls" "fmt" "net/http" + "time" "github.com/docker/machine/log" + "github.com/docker/machine/utils" "github.com/docker/machine/version" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack" @@ -31,7 +33,7 @@ type Client interface { StopInstance(d *Driver) error RestartInstance(d *Driver) error DeleteInstance(d *Driver) error - WaitForInstanceStatus(d *Driver, status string, timeout int) error + WaitForInstanceStatus(d *Driver, status string) error GetInstanceIpAddresses(d *Driver) ([]IpAddress, error) CreateKeyPair(d *Driver, name string, publicKey string) error DeleteKeyPair(d *Driver, name string) error @@ -132,11 +134,23 @@ func (c *GenericClient) DeleteInstance(d *Driver) error { return nil } -func (c *GenericClient) WaitForInstanceStatus(d *Driver, status string, timeout int) error { - if err := servers.WaitForStatus(c.Compute, d.MachineId, status, timeout); err != nil { - return err - } - return nil +func (c *GenericClient) WaitForInstanceStatus(d *Driver, status string) error { + return utils.WaitForSpecificOrError(func() (bool, error) { + current, err := servers.Get(c.Compute, d.MachineId).Extract() + if err != nil { + return true, err + } + + if current.Status == "ERROR" { + return true, fmt.Errorf("Instance creation failed. Instance is in ERROR state") + } + + if current.Status == status { + return true, nil + } + + return false, nil + }, 50, 4*time.Second) } func (c *GenericClient) GetInstanceIpAddresses(d *Driver) ([]IpAddress, error) { diff --git a/drivers/openstack/openstack.go b/drivers/openstack/openstack.go index d6e6bdf8..2bba3e5e 100644 --- a/drivers/openstack/openstack.go +++ b/drivers/openstack/openstack.go @@ -664,7 +664,7 @@ func (d *Driver) assignFloatingIp() error { func (d *Driver) waitForInstanceActive() error { log.WithField("MachineId", d.MachineId).Debug("Waiting for the OpenStack instance to be ACTIVE...") - if err := d.client.WaitForInstanceStatus(d, "ACTIVE", 200); err != nil { + if err := d.client.WaitForInstanceStatus(d, "ACTIVE"); err != nil { return err } return nil