use separate log table

This commit is contained in:
Brad Rydzewski 2017-04-03 18:34:37 +09:00
parent ec88661d9e
commit 0daee76aa8
7 changed files with 147 additions and 124 deletions

View file

@ -1,7 +0,0 @@
package model
// type Log struct {
// ID int64 `meddler:"log_id,pk"`
// JobID int64 `meddler:"log_job_id"`
// Data []byte `meddler:"log_data"`
// }

View file

@ -104,7 +104,7 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
repo.GET("", server.GetRepo)
repo.GET("/builds", server.GetBuilds)
repo.GET("/builds/:number", server.GetBuild)
repo.GET("/logs/:number/:job", server.GetBuildLogs)
repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs)
repo.POST("/sign", session.MustPush, server.Sign)
repo.GET("/secrets", session.MustPush, server.GetSecrets)

View file

@ -77,7 +77,8 @@ func GetBuildLogs(c *gin.Context) {
// parse the build number and job sequence number from
// the repquest parameter.
num, _ := strconv.Atoi(c.Params.ByName("number"))
seq, _ := strconv.Atoi(c.Params.ByName("job"))
ppid, _ := strconv.Atoi(c.Params.ByName("ppid"))
name := c.Params.ByName("proc")
build, err := store.GetBuildNumber(c, repo, num)
if err != nil {
@ -85,13 +86,13 @@ func GetBuildLogs(c *gin.Context) {
return
}
proc, err := store.FromContext(c).ProcFind(build, seq)
proc, err := store.FromContext(c).ProcChild(build, ppid, name)
if err != nil {
c.AbortWithError(404, err)
return
}
rc, err := store.FromContext(c).FileRead(proc, "logs.json")
rc, err := store.FromContext(c).LogFind(proc)
if err != nil {
c.AbortWithError(404, err)
return

View file

@ -111,15 +111,21 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
return err
}
proc, err := s.store.ProcLoad(procID)
pproc, err := s.store.ProcLoad(procID)
if err != nil {
log.Printf("error: rpc.update: cannot find proc with id %d: %s", procID, err)
log.Printf("error: rpc.update: cannot find pproc with id %d: %s", procID, err)
return err
}
build, err := s.store.GetBuild(proc.BuildID)
build, err := s.store.GetBuild(pproc.BuildID)
if err != nil {
log.Printf("error: cannot find build with id %d: %s", proc.BuildID, err)
log.Printf("error: cannot find build with id %d: %s", pproc.BuildID, err)
return err
}
proc, err := s.store.ProcChild(build, pproc.PID, state.Proc)
if err != nil {
log.Printf("error: cannot find proc with name %s: %s", state.Proc, err)
return err
}
@ -133,6 +139,10 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
proc.Stopped = state.Finished
proc.ExitCode = state.ExitCode
proc.Error = state.Error
proc.State = model.StatusSuccess
if state.ExitCode != 0 || state.Error != "" {
proc.State = model.StatusFailure
}
} else {
proc.Started = state.Started
proc.State = model.StatusRunning
@ -165,12 +175,31 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
return err
}
proc, err := s.store.ProcLoad(procID)
pproc, err := s.store.ProcLoad(procID)
if err != nil {
log.Printf("error: cannot find proc with id %d: %s", procID, err)
log.Printf("error: cannot find parent proc with id %d: %s", procID, err)
return err
}
build, err := s.store.GetBuild(pproc.BuildID)
if err != nil {
log.Printf("error: cannot find build with id %d: %s", pproc.BuildID, err)
return err
}
proc, err := s.store.ProcChild(build, pproc.PID, file.Proc)
if err != nil {
log.Printf("error: cannot find child proc with name %s: %s", file.Proc, err)
return err
}
if file.Mime == "application/json+logs" {
return s.store.LogSave(
proc,
bytes.NewBuffer(file.Data),
)
}
return s.store.FileCreate(&model.File{
BuildID: proc.BuildID,
ProcID: proc.ID,
@ -261,19 +290,13 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
return err
}
if build.Status == model.StatusPending {
build.Status = model.StatusRunning
build.Started = state.Started
if err := s.store.UpdateBuild(build); err != nil {
log.Printf("error: done: cannot update build_id %d state: %s", build.ID, err)
}
}
proc.Started = state.Started
proc.State = model.StatusRunning
proc.Stopped = state.Finished
proc.Error = state.Error
proc.ExitCode = state.ExitCode
proc.State = model.StatusSuccess
if proc.ExitCode != 0 || proc.Error != "" {
proc.State = model.StatusFailure
}
if err := s.store.ProcUpdate(proc); err != nil {
log.Printf("error: done: cannot update proc_id %d state: %s", procID, err)
}
@ -287,7 +310,7 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
// TODO handle this error
procs, _ := s.store.ProcList(build)
for _, p := range procs {
if !proc.Running() && p.PPID == proc.PID {
if p.Running() && p.PPID == proc.PID {
p.State = model.StatusSkipped
if p.Started != 0 {
p.State = model.StatusKilled
@ -297,12 +320,11 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
log.Printf("error: done: cannot update proc_id %d child state: %s", p.ID, err)
}
}
if !proc.Running() && p.PPID == 0 {
if !p.Running() && p.PPID == 0 {
done = true
if p.Failing() {
status = model.StatusFailure
}
continue
}
}
if done {

View file

@ -1,37 +1,42 @@
package datastore
//
// import (
// "bytes"
// "io"
// "io/ioutil"
//
// "github.com/drone/drone/model"
// "github.com/russross/meddler"
// )
//
// func (db *datastore) ReadLog(job *model.Job) (io.ReadCloser, error) {
// var log = new(model.Log)
// var err = meddler.QueryRow(db, log, rebind(logQuery), job.ID)
// var buf = bytes.NewBuffer(log.Data)
// return ioutil.NopCloser(buf), err
// }
//
// func (db *datastore) WriteLog(job *model.Job, r io.Reader) error {
// var log = new(model.Log)
// var err = meddler.QueryRow(db, log, rebind(logQuery), job.ID)
// if err != nil {
// log = &model.Log{JobID: job.ID}
// }
// log.Data, _ = ioutil.ReadAll(r)
// return meddler.Save(db, logTable, log)
// }
//
// const logTable = "logs"
//
// const logQuery = `
// SELECT *
// FROM logs
// WHERE log_job_id=?
// LIMIT 1
// `
import (
"bytes"
"io"
"io/ioutil"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
func (db *datastore) LogFind(proc *model.Proc) (io.ReadCloser, error) {
var log = new(logData)
var err = meddler.QueryRow(db, log, rebind(logQuery), proc.ID)
var buf = bytes.NewBuffer(log.Data)
return ioutil.NopCloser(buf), err
}
func (db *datastore) LogSave(proc *model.Proc, r io.Reader) error {
var log = new(logData)
var err = meddler.QueryRow(db, log, rebind(logQuery), proc.ID)
if err != nil {
log = &logData{ProcID: proc.ID}
}
log.Data, _ = ioutil.ReadAll(r)
return meddler.Save(db, logTable, log)
}
type logData struct {
ID int64 `meddler:"log_id,pk"`
ProcID int64 `meddler:"log_job_id"`
Data []byte `meddler:"log_data"`
}
const logTable = "logs"
const logQuery = `
SELECT *
FROM logs
WHERE log_job_id=?
LIMIT 1
`

View file

@ -1,61 +1,60 @@
package datastore
//
// import (
// "bytes"
// "io/ioutil"
// "testing"
//
// "github.com/drone/drone/model"
// "github.com/franela/goblin"
// )
//
// func TestLogs(t *testing.T) {
// db := openTest()
// defer db.Close()
//
// s := From(db)
// g := goblin.Goblin(t)
// g.Describe("Logs", func() {
//
// // before each test be sure to purge the package
// // table data from the database.
// g.BeforeEach(func() {
// db.Exec("DELETE FROM logs")
// })
//
// g.It("Should create a log", func() {
// job := model.Job{
// ID: 1,
// }
// buf := bytes.NewBufferString("echo hi")
// err := s.WriteLog(&job, buf)
// g.Assert(err == nil).IsTrue()
//
// rc, err := s.ReadLog(&job)
// g.Assert(err == nil).IsTrue()
// defer rc.Close()
// out, _ := ioutil.ReadAll(rc)
// g.Assert(string(out)).Equal("echo hi")
// })
//
// g.It("Should update a log", func() {
// job := model.Job{
// ID: 1,
// }
// buf1 := bytes.NewBufferString("echo hi")
// buf2 := bytes.NewBufferString("echo allo?")
// err1 := s.WriteLog(&job, buf1)
// err2 := s.WriteLog(&job, buf2)
// g.Assert(err1 == nil).IsTrue()
// g.Assert(err2 == nil).IsTrue()
//
// rc, err := s.ReadLog(&job)
// g.Assert(err == nil).IsTrue()
// defer rc.Close()
// out, _ := ioutil.ReadAll(rc)
// g.Assert(string(out)).Equal("echo allo?")
// })
//
// })
// }
import (
"bytes"
"io/ioutil"
"testing"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestLogs(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("Logs", func() {
// before each test be sure to purge the package
// table data from the database.
g.BeforeEach(func() {
db.Exec("DELETE FROM logs")
})
g.It("Should create a log", func() {
proc := model.Proc{
ID: 1,
}
buf := bytes.NewBufferString("echo hi")
err := s.LogSave(&proc, buf)
g.Assert(err == nil).IsTrue()
rc, err := s.LogFind(&proc)
g.Assert(err == nil).IsTrue()
defer rc.Close()
out, _ := ioutil.ReadAll(rc)
g.Assert(string(out)).Equal("echo hi")
})
g.It("Should update a log", func() {
proc := model.Proc{
ID: 1,
}
buf1 := bytes.NewBufferString("echo hi")
buf2 := bytes.NewBufferString("echo allo?")
err1 := s.LogSave(&proc, buf1)
err2 := s.LogSave(&proc, buf2)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
rc, err := s.LogFind(&proc)
g.Assert(err == nil).IsTrue()
defer rc.Close()
out, _ := ioutil.ReadAll(rc)
g.Assert(string(out)).Equal("echo allo?")
})
})
}

View file

@ -152,6 +152,9 @@ type Store interface {
ProcCreate([]*model.Proc) error
ProcUpdate(*model.Proc) error
LogFind(*model.Proc) (io.ReadCloser, error)
LogSave(*model.Proc, io.Reader) error
FileList(*model.Build) ([]*model.File, error)
FileFind(*model.Proc, string) (*model.File, error)
FileRead(*model.Proc, string) (io.ReadCloser, error)