Merge pull request #784 from hairyhenderson/softlayer-wait-for-transactions

Wait for any activeTransactions to finish during Create
This commit is contained in:
Evan Hazlett 2015-03-17 12:15:54 -04:00
commit ca8ae29ad2
2 changed files with 114 additions and 43 deletions

View File

@ -295,27 +295,37 @@ func (d *Driver) GetState() (state.State, error) {
return vmState, nil return vmState, nil
} }
func (d *Driver) GetActiveTransaction() (string, error) {
t, err := d.getClient().VirtualGuest().ActiveTransaction(d.Id)
if err != nil {
return "", err
}
return t, nil
}
func (d *Driver) PreCreateCheck() error { func (d *Driver) PreCreateCheck() error {
return nil return nil
} }
func (d *Driver) Create() error { func (d *Driver) waitForStart() {
waitForStart := func() {
log.Infof("Waiting for host to become available") log.Infof("Waiting for host to become available")
for { for {
s, err := d.GetState() s, err := d.GetState()
if err != nil { if err != nil {
log.Debugf("Failed to GetState - %+v", err)
continue continue
} }
if s == state.Running { if s == state.Running {
break break
} else {
log.Debugf("Still waiting - state is %s...", s)
} }
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
} }
} }
getIp := func() { func (d *Driver) getIp() (string, error) {
log.Infof("Getting Host IP") log.Infof("Getting Host IP")
for { for {
var ( var (
@ -334,13 +344,40 @@ func (d *Driver) Create() error {
// not a perfect regex, but should be just fine for our needs // not a perfect regex, but should be just fine for our needs
exp := regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`) exp := regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
if exp.MatchString(ip) { if exp.MatchString(ip) {
d.IPAddress = ip return ip, nil
break
} }
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
} }
} }
func (d *Driver) waitForSetupTransactions() {
log.Infof("Waiting for host setup transactions to complete")
// sometimes we'll hit a case where there's no active transaction, but if
// we check again in a few seconds, it moves to the next transaction. We
// don't want to get false-positives, so we check a few times in a row to make sure!
noActiveCount, maxNoActiveCount := 0, 3
for {
t, err := d.GetActiveTransaction()
if err != nil {
noActiveCount = 0
log.Debugf("Failed to GetActiveTransaction - %+v", err)
continue
}
if t == "" {
if noActiveCount == maxNoActiveCount {
break
}
noActiveCount++
} else {
noActiveCount = 0
log.Debugf("Still waiting - active transaction is %s...", t)
}
time.Sleep(2 * time.Second)
}
}
func (d *Driver) Create() error {
log.Infof("Creating SSH key...") log.Infof("Creating SSH key...")
key, err := d.createSSHKey() key, err := d.createSSHKey()
if err != nil { if err != nil {
@ -355,8 +392,9 @@ func (d *Driver) Create() error {
return fmt.Errorf("Error creating host: %q", err) return fmt.Errorf("Error creating host: %q", err)
} }
d.Id = id d.Id = id
getIp() d.getIp()
waitForStart() d.waitForStart()
d.waitForSetupTransactions()
ssh.WaitForTCP(d.IPAddress + ":22") ssh.WaitForTCP(d.IPAddress + ":22")
cmd, err := drivers.GetSSHCommandFromDriver(d, "sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq curl") cmd, err := drivers.GetSSHCommandFromDriver(d, "sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq curl")

View File

@ -180,6 +180,39 @@ func (c *virtualGuest) PowerState(id int) (string, error) {
return s.Name, nil return s.Name, nil
} }
func (c *virtualGuest) ActiveTransaction(id int) (string, error) {
type transactionStatus struct {
AverageDuration string `json:"averageDuration"`
FriendlyName string `json:"friendlyName"`
Name string `json:"name"`
}
type transaction struct {
CreateDate string `json:"createDate"`
ElapsedSeconds int `json:"elapsedSeconds"`
GuestID int `json:"guestId"`
HardwareID int `json:"hardwareId"`
ID int `json:"id"`
ModifyDate string `json:"modifyDate"`
StatusChangeDate string `json:"statusChangeDate"`
TransactionStatus transactionStatus `json:"transactionStatus"`
}
var (
method = "GET"
uri = fmt.Sprintf("%s/%v/getActiveTransaction.json", c.namespace(), id)
)
data, err := c.newRequest(method, uri, nil)
if err != nil {
return "", err
}
var t transaction
if err := json.Unmarshal(data, &t); err != nil {
return "", err
}
return t.TransactionStatus.Name, nil
}
func (c *virtualGuest) Create(spec *HostSpec) (int, error) { func (c *virtualGuest) Create(spec *HostSpec) (int, error) {
var ( var (
method = "POST" method = "POST"