2024-02-20 13:25:31 +00:00
|
|
|
package daemon
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2024-02-27 02:00:07 +00:00
|
|
|
"time"
|
2024-02-20 13:25:31 +00:00
|
|
|
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/api"
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/artifact"
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/daemon/db"
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/distro"
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/qemu"
|
|
|
|
)
|
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
type jobProcessor struct {
|
2024-02-20 13:25:31 +00:00
|
|
|
job api.Job
|
|
|
|
log zerolog.Logger
|
|
|
|
db *sql.DB
|
|
|
|
}
|
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
func newJobProcessor(job api.Job, db *sql.DB) (pj jobProcessor) {
|
2024-02-20 13:25:31 +00:00
|
|
|
pj.job = job
|
|
|
|
pj.db = db
|
2024-02-26 08:55:27 +00:00
|
|
|
pj.log = log.With().
|
|
|
|
Str("uuid", job.UUID).
|
|
|
|
Str("group", job.Group).
|
|
|
|
Logger()
|
2024-02-20 13:25:31 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
func (pj jobProcessor) Update() (err error) {
|
2024-02-26 08:55:27 +00:00
|
|
|
err = db.UpdateJob(pj.db, &pj.job)
|
2024-02-20 13:25:31 +00:00
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Err(err).Msgf("update job %v", pj.job)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
func (pj jobProcessor) SetStatus(status api.Status) (err error) {
|
2024-02-20 13:25:31 +00:00
|
|
|
pj.log.Info().Msgf(`%v -> %v`, pj.job.Status, status)
|
|
|
|
pj.job.Status = status
|
|
|
|
err = pj.Update()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
func (pj *jobProcessor) Process(res *Resources) (err error) {
|
|
|
|
if pj.job.Status != api.StatusWaiting {
|
|
|
|
err = errors.New("job is not available to process")
|
2024-02-20 13:25:31 +00:00
|
|
|
return
|
2024-02-25 18:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if pj.job.Artifact.Qemu.Cpus == 0 {
|
|
|
|
pj.job.Artifact.Qemu.Cpus = qemu.DefaultCPUs
|
|
|
|
}
|
|
|
|
|
|
|
|
if pj.job.Artifact.Qemu.Memory == 0 {
|
|
|
|
pj.job.Artifact.Qemu.Memory = qemu.DefaultMemory
|
|
|
|
}
|
|
|
|
|
|
|
|
err = res.Allocate(pj.job)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
res.Release(pj.job)
|
|
|
|
}()
|
|
|
|
|
|
|
|
log.Info().Msgf("process job %v", pj.job.UUID)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
pj.SetStatus(api.StatusRunning)
|
2024-02-27 02:00:07 +00:00
|
|
|
pj.job.Started = time.Now()
|
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
defer func() {
|
2024-02-27 02:00:07 +00:00
|
|
|
pj.job.Finished = time.Now()
|
2024-02-20 13:25:31 +00:00
|
|
|
if err != nil {
|
2024-02-25 18:04:02 +00:00
|
|
|
pj.SetStatus(api.StatusFailure)
|
|
|
|
} else {
|
|
|
|
pj.SetStatus(api.StatusSuccess)
|
2024-02-20 13:25:31 +00:00
|
|
|
}
|
2024-02-25 18:04:02 +00:00
|
|
|
}()
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
var tmp string
|
|
|
|
tmp, err = os.MkdirTemp(dotfiles.Dir("tmp"), "")
|
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Err(err).Msg("mktemp")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmp)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
tmprepo := filepath.Join(tmp, "repo")
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
pj.log.Debug().Msgf("temp repo: %v", tmprepo)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
remote := fmt.Sprintf("git://localhost:9418/%s", pj.job.RepoName)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
pj.log.Debug().Msgf("remote: %v", remote)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
var raw []byte
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
cmd := exec.Command("git", "clone", remote, tmprepo)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
raw, err = cmd.CombinedOutput()
|
|
|
|
pj.log.Trace().Msgf("%v\n%v", cmd, string(raw))
|
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Msgf("%v\n%v", cmd, string(raw))
|
|
|
|
return
|
|
|
|
}
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
cmd = exec.Command("git", "checkout", pj.job.Commit)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
cmd.Dir = tmprepo
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
raw, err = cmd.CombinedOutput()
|
|
|
|
pj.log.Trace().Msgf("%v\n%v", cmd, string(raw))
|
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Msgf("%v\n%v", cmd, string(raw))
|
|
|
|
return
|
|
|
|
}
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
pj.job.Artifact.SourcePath = tmprepo
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
var result *artifact.Result
|
|
|
|
var dq *qemu.System
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
pj.job.Artifact.Process(pj.log, pj.job.Target, false, "", "", 0,
|
|
|
|
func(q *qemu.System, ka artifact.Artifact, ki distro.KernelInfo,
|
|
|
|
res *artifact.Result) {
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
result = res
|
|
|
|
dq = q
|
|
|
|
},
|
|
|
|
)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
logdir := dotfiles.Dir("daemon/logs", pj.job.UUID)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
err = os.WriteFile(filepath.Join(logdir, "build.log"),
|
|
|
|
[]byte(result.Build.Output), 0644)
|
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Err(err).Msg("")
|
|
|
|
}
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
err = os.WriteFile(filepath.Join(logdir, "run.log"),
|
|
|
|
[]byte(result.Run.Output), 0644)
|
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Err(err).Msg("")
|
|
|
|
}
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
err = os.WriteFile(filepath.Join(logdir, "test.log"),
|
|
|
|
[]byte(result.Test.Output), 0644)
|
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Err(err).Msg("")
|
|
|
|
}
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
err = os.WriteFile(filepath.Join(logdir, "qemu.log"),
|
|
|
|
[]byte(dq.Stdout), 0644)
|
|
|
|
if err != nil {
|
|
|
|
pj.log.Error().Err(err).Msg("")
|
|
|
|
}
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
pj.log.Info().Msgf("build %v, run %v, test %v",
|
|
|
|
result.Build.Ok, result.Run.Ok, result.Test.Ok)
|
2024-02-20 13:25:31 +00:00
|
|
|
|
2024-02-25 18:04:02 +00:00
|
|
|
if !result.Test.Ok {
|
|
|
|
err = errors.New("tests failed")
|
2024-02-20 13:25:31 +00:00
|
|
|
}
|
2024-02-25 18:04:02 +00:00
|
|
|
|
2024-02-20 13:25:31 +00:00
|
|
|
return
|
|
|
|
}
|