Commit 0e50b6e5 authored by Kamil Trzciński's avatar Kamil Trzciński

Read build trace in safer way and also limit amount read

parent fc4488da
package common
import (
"bytes"
"errors"
"fmt"
"io"
......@@ -114,15 +113,46 @@ func (b *Build) FinishBuild(buildState BuildState, buildMessage string, args ...
b.BuildDuration = b.BuildFinished.Sub(b.BuildStarted)
}
func (b *Build) ReadBuildLog() (string, error) {
maxTraceSize := MaxTraceOutputSize
if b.BuildLog == "" {
return "", errors.New("no build log")
}
file, err := os.Open(b.BuildLog)
if err != nil {
return "", err
}
defer file.Close()
limitReader := io.LimitReader(file, maxTraceSize)
data, err := ioutil.ReadAll(limitReader)
if err != nil {
return "", err
}
buildTrace := string(data)
if fi, err := file.Stat(); err == nil && fi.Size() > maxTraceSize {
buildLogExceeded := fmt.Sprintf("\nBuild log exceed limit of %v bytes.", maxTraceSize)
buildTrace = buildTrace + buildLogExceeded
}
return buildTrace, nil
}
func (b *Build) SendBuildLog() {
var buildLog []byte
if b.BuildLog != "" {
buildLog, _ = ioutil.ReadFile(b.BuildLog)
var buildTrace string
buildTrace, err := b.ReadBuildLog()
if err != nil {
buildTrace = "Failed to read build trace: " + err.Error()
}
if b.BuildMessage != "" {
buildTrace = buildTrace + b.BuildMessage
}
for {
buffer := io.MultiReader(bytes.NewReader(buildLog), bytes.NewBufferString(b.BuildMessage))
if UpdateBuild(*b.Runner, b.ID, b.BuildState, buffer) != UpdateFailed {
if UpdateBuild(*b.Runner, b.ID, b.BuildState, buildTrace) != UpdateFailed {
break
} else {
time.Sleep(UpdateRetryInterval * time.Second)
......
......@@ -10,3 +10,4 @@ const HealthyChecks = 3
const HealthCheckInterval = 3600
const DefaultWaitForServicesTimeout = 30
const ShutdownTimeout = 30
const MaxTraceOutputSize int64 = 1024 * 1024 // 1MB
......@@ -213,16 +213,11 @@ func VerifyRunner(url, token string) bool {
}
}
func UpdateBuild(config RunnerConfig, id int, state BuildState, trace io.Reader) UpdateState {
data, err := readPayload(trace)
if err != nil {
return UpdateFailed
}
func UpdateBuild(config RunnerConfig, id int, state BuildState, trace string) UpdateState {
request := UpdateBuildRequest{
Token: config.Token,
State: state,
Trace: string(data),
Trace: trace,
}
result := putJSON(getURL(config.URL, "builds/%d.json", id), 200, &request, nil)
......
......@@ -30,29 +30,16 @@ func (e *AbstractExecutor) WatchTrace(config common.RunnerConfig, canceled chan
return
}
file, err := os.Open(buildLog.Name())
if err != nil {
e.Errorln("Failed to read", buildLog.Name(), err)
<-finished
return
}
defer file.Close()
for {
select {
case <-time.After(common.UpdateInterval * time.Second):
if e.BuildLog == nil {
<-finished
return
}
offset, err := file.Seek(0, 0)
if err != nil || offset != 0 {
e.Debugln("updateBuildLog", "Failed to seek build log to the beggining...", offset, err)
buildTrace, err := e.Build.ReadBuildLog()
if err != nil {
e.Debugln("updateBuildLog", "Failed to read build log...", err)
continue
}
switch common.UpdateBuild(config, e.Build.ID, common.Running, file) {
switch common.UpdateBuild(config, e.Build.ID, common.Running, buildTrace) {
case common.UpdateSucceeded:
case common.UpdateAbort:
e.Debugln("updateBuildLog", "Sending abort request...")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment