in step_wait_for_instances_signal.go [151:235]
func waitForSerialOutput(s *Step, project, zone, name string, so *SerialOutput, interval time.Duration) DError {
w := s.w
msg := fmt.Sprintf("Instance %q: watching serial port %d", name, so.Port)
if so.SuccessMatch != "" {
msg += fmt.Sprintf(", SuccessMatch: %q", so.SuccessMatch)
}
if len(so.FailureMatch) > 0 {
msg += fmt.Sprintf(", FailureMatch: %q (this is not an error)", so.FailureMatch)
}
if so.StatusMatch != "" {
msg += fmt.Sprintf(", StatusMatch: %q", so.StatusMatch)
}
w.LogStepInfo(s.name, "WaitForInstancesSignal", msg+".")
var start int64
var errs int
tailString := ""
tick := time.Tick(interval)
for {
select {
case <-s.w.Cancel:
return nil
case <-tick:
resp, err := w.ComputeClient.GetSerialPortOutput(project, zone, name, so.Port, start)
if err != nil {
status, sErr := w.ComputeClient.InstanceStatus(project, zone, name)
if sErr != nil {
err = fmt.Errorf("%v, error getting InstanceStatus: %v", err, sErr)
} else {
err = fmt.Errorf("%v, InstanceStatus: %q", err, status)
}
// Wait until machine restarts to evaluate SerialOutput.
if status == "TERMINATED" || status == "STOPPED" || status == "STOPPING" {
continue
}
// Retry up to 3 times in a row on any error if we successfully got InstanceStatus.
if errs < 3 {
errs++
continue
}
return Errf("WaitForInstancesSignal: instance %q: error getting serial port: %v", name, err)
}
start = resp.Next
lines := strings.Split(resp.Contents, "\n")
for i, ln := range lines {
// If there is a unconsumed tail string from the previous block of content, concat it with the 1st line of the new block of content.
if i == 0 && tailString != "" {
ln = tailString + ln
tailString = ""
}
// If the content is not ended with a "\n", we want to store the last line as tail string, so it can be concat with the next block of content.
if i == len(lines)-1 && lines[len(lines)-1] != "" {
tailString = ln
break
}
if so.StatusMatch != "" {
if i := strings.Index(ln, so.StatusMatch); i != -1 {
w.LogStepInfo(s.name, "WaitForInstancesSignal", "Instance %q: StatusMatch found: %q", name, strings.TrimSpace(ln[i:]))
extractOutputValue(w, ln)
}
}
if len(so.FailureMatch) > 0 {
for _, failureMatch := range so.FailureMatch {
if i := strings.Index(ln, failureMatch); i != -1 {
errMsg := strings.TrimSpace(ln[i:])
format := "WaitForInstancesSignal FailureMatch found for %q: %q"
return newErr(errMsg, fmt.Errorf(format, name, errMsg))
}
}
}
if so.SuccessMatch != "" {
if i := strings.Index(ln, so.SuccessMatch); i != -1 {
w.LogStepInfo(s.name, "WaitForInstancesSignal", "Instance %q: SuccessMatch found %q", name, strings.TrimSpace(ln[i:]))
return nil
}
}
}
errs = 0
}
}
}