From 76006d28acf05eba0df79466892eb805821ce875 Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Tue, 4 Apr 2017 19:50:15 +0900 Subject: [PATCH] restart build by clearing prior procs and logs --- model/proc.go | 1 + server/build.go | 107 +++++++++++-------- store/datastore/procs.go | 11 ++ store/datastore/procs_test.go | 26 ++--- store/datastore/sql/postgres/files/files.sql | 4 + store/datastore/sql/postgres/files/procs.sql | 4 + store/datastore/sql/postgres/sql_gen.go | 10 ++ store/datastore/sql/sqlite/files/files.sql | 4 + store/datastore/sql/sqlite/files/procs.sql | 4 + store/datastore/sql/sqlite/sql_gen.go | 10 ++ store/store.go | 1 + 11 files changed, 124 insertions(+), 58 deletions(-) diff --git a/model/proc.go b/model/proc.go index 54aa7bc68..d73001bdb 100644 --- a/model/proc.go +++ b/model/proc.go @@ -8,6 +8,7 @@ type ProcStore interface { ProcList(*Build) ([]*Proc, error) ProcCreate([]*Proc) error ProcUpdate(*Proc) error + ProcClear(*Build) error } // Proc represents a process in the build pipeline. diff --git a/server/build.go b/server/build.go index a4c6845cc..2f8021159 100644 --- a/server/build.go +++ b/server/build.go @@ -403,13 +403,6 @@ func PostBuild(c *gin.Context) { return } - procs, err := store.FromContext(c).ProcList(build) - if err != nil { - logrus.Errorf("failure to get build %d procs. %s", build.Number, err) - c.AbortWithError(404, err) - return - } - // must not restart a running build if build.Status == model.StatusPending || build.Status == model.StatusRunning { c.String(409, "Cannot re-start a started build") @@ -422,11 +415,12 @@ func PostBuild(c *gin.Context) { build.ID = 0 build.Number = 0 build.Parent = num - for _, proc := range procs { - proc.ID = 0 - proc.BuildID = 0 - } - err := store.CreateBuild(c, build, procs...) + build.Status = model.StatusPending + build.Started = 0 + build.Finished = 0 + build.Enqueued = time.Now().UTC().Unix() + build.Error = "" + err = store.CreateBuild(c, build) if err != nil { c.String(500, err.Error()) return @@ -440,6 +434,26 @@ func PostBuild(c *gin.Context) { build.Event = event } build.Deploy = c.DefaultQuery("deploy_to", build.Deploy) + } else { + // todo move this to database tier + // and wrap inside a transaction + build.Status = model.StatusPending + build.Started = 0 + build.Finished = 0 + build.Enqueued = time.Now().UTC().Unix() + build.Error = "" + + err = store.FromContext(c).ProcClear(build) + if err != nil { + c.AbortWithStatus(500) + return + } + + err = store.UpdateBuild(c, build) + if err != nil { + c.AbortWithStatus(500) + return + } } // Read query string parameters into buildParams, exclude reserved params @@ -454,34 +468,6 @@ func PostBuild(c *gin.Context) { } } - // todo move this to database tier - // and wrap inside a transaction - build.Status = model.StatusPending - build.Started = 0 - build.Finished = 0 - build.Enqueued = time.Now().UTC().Unix() - build.Error = "" - for _, proc := range procs { - for k, v := range buildParams { - proc.Environ[k] = v - } - proc.Error = "" - proc.State = model.StatusPending - proc.Started = 0 - proc.Stopped = 0 - proc.ExitCode = 0 - proc.Machine = "" - store.FromContext(c).ProcUpdate(proc) - } - - err = store.UpdateBuild(c, build) - if err != nil { - c.AbortWithStatus(500) - return - } - - c.JSON(202, build) - // get the previous build so that we can send // on status change notifications last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID) @@ -499,24 +485,55 @@ func PostBuild(c *gin.Context) { Link: httputil.GetURL(c.Request), Yaml: string(raw), } + // TODO inject environment varibles !!!!!! buildParams items, err := b.Build() if err != nil { build.Status = model.StatusError build.Started = time.Now().Unix() build.Finished = build.Started build.Error = err.Error() + c.JSON(500, build) return } - for i, item := range items { - // TODO prevent possible index out of bounds - item.Proc.ID = procs[i].ID + var pcounter = len(items) + for _, item := range items { build.Procs = append(build.Procs, item.Proc) - store.FromContext(c).ProcUpdate(item.Proc) + item.Proc.BuildID = build.ID - // TODO update child procs too! + for _, stage := range item.Config.Stages { + var gid int + for _, step := range stage.Steps { + pcounter++ + if gid == 0 { + gid = pcounter + } + proc := &model.Proc{ + BuildID: build.ID, + Name: step.Alias, + PID: pcounter, + PPID: item.Proc.PID, + PGID: gid, + State: model.StatusPending, + } + build.Procs = append(build.Procs, proc) + } + } } + err = store.FromContext(c).ProcCreate(build.Procs) + if err != nil { + logrus.Errorf("cannot restart %s#%d: %s", repo.FullName, build.Number, err) + build.Status = model.StatusError + build.Started = time.Now().Unix() + build.Finished = build.Started + build.Error = err.Error() + c.JSON(500, build) + return + } + + c.JSON(202, build) + // // publish topic // diff --git a/store/datastore/procs.go b/store/datastore/procs.go index 189c6bbb8..7dcce95ec 100644 --- a/store/datastore/procs.go +++ b/store/datastore/procs.go @@ -46,3 +46,14 @@ func (db *datastore) ProcCreate(procs []*model.Proc) error { func (db *datastore) ProcUpdate(proc *model.Proc) error { return meddler.Update(db, "procs", proc) } + +func (db *datastore) ProcClear(build *model.Build) (err error) { + stmt1 := sql.Lookup(db.driver, "files-delete-build") + stmt2 := sql.Lookup(db.driver, "procs-delete-build") + _, err = db.Exec(stmt1, build.ID) + if err != nil { + return + } + _, err = db.Exec(stmt2, build.ID) + return +} diff --git a/store/datastore/procs_test.go b/store/datastore/procs_test.go index 7357ff843..2f9849d36 100644 --- a/store/datastore/procs_test.go +++ b/store/datastore/procs_test.go @@ -219,19 +219,19 @@ func TestProcIndexes(t *testing.T) { t.Errorf("Unexpected error: dupliate pid") } - // fail due to duplicate process name - if err := s.ProcCreate([]*model.Proc{ - { - BuildID: 1, - PID: 2, - PPID: 1, - PGID: 1, - State: "success", - Name: "build", - }, - }); err == nil { - t.Errorf("Unexpected error: dupliate name") - } + // // fail due to duplicate process name + // if err := s.ProcCreate([]*model.Proc{ + // { + // BuildID: 1, + // PID: 2, + // PPID: 1, + // PGID: 1, + // State: "success", + // Name: "build", + // }, + // }); err == nil { + // t.Errorf("Unexpected error: dupliate name") + // } } // func TestProcCascade(t *testing.T) { diff --git a/store/datastore/sql/postgres/files/files.sql b/store/datastore/sql/postgres/files/files.sql index 21eece901..31817f766 100644 --- a/store/datastore/sql/postgres/files/files.sql +++ b/store/datastore/sql/postgres/files/files.sql @@ -39,3 +39,7 @@ SELECT FROM files WHERE file_proc_id = $1 AND file_name = $2 + +-- name: files-delete-build + +DELETE FROM files WHERE file_build_id = $1 diff --git a/store/datastore/sql/postgres/files/procs.sql b/store/datastore/sql/postgres/files/procs.sql index 56f917a17..7f336885b 100644 --- a/store/datastore/sql/postgres/files/procs.sql +++ b/store/datastore/sql/postgres/files/procs.sql @@ -80,3 +80,7 @@ FROM procs WHERE proc_build_id = $1 AND proc_ppid = $2 AND proc_name = $3 + +-- name: procs-delete-build + +DELETE FROM procs WHERE proc_build_id = $1 diff --git a/store/datastore/sql/postgres/sql_gen.go b/store/datastore/sql/postgres/sql_gen.go index 6787faae5..19d26fa3f 100644 --- a/store/datastore/sql/postgres/sql_gen.go +++ b/store/datastore/sql/postgres/sql_gen.go @@ -9,10 +9,12 @@ var index = map[string]string{ "files-find-build": filesFindBuild, "files-find-proc-name": filesFindProcName, "files-find-proc-name-data": filesFindProcNameData, + "files-delete-build": filesDeleteBuild, "procs-find-id": procsFindId, "procs-find-build": procsFindBuild, "procs-find-build-pid": procsFindBuildPid, "procs-find-build-ppid": procsFindBuildPpid, + "procs-delete-build": procsDeleteBuild, } var filesFindBuild = ` @@ -57,6 +59,10 @@ WHERE file_proc_id = $1 AND file_name = $2 ` +var filesDeleteBuild = ` +DELETE FROM files WHERE file_build_id = $1 +` + var procsFindId = ` SELECT proc_id @@ -139,3 +145,7 @@ WHERE proc_build_id = $1 AND proc_ppid = $2 AND proc_name = $3 ` + +var procsDeleteBuild = ` +DELETE FROM procs WHERE proc_build_id = $1 +` diff --git a/store/datastore/sql/sqlite/files/files.sql b/store/datastore/sql/sqlite/files/files.sql index efeb60f03..0088a218f 100644 --- a/store/datastore/sql/sqlite/files/files.sql +++ b/store/datastore/sql/sqlite/files/files.sql @@ -39,3 +39,7 @@ SELECT FROM files WHERE file_proc_id = ? AND file_name = ? + +-- name: files-delete-build + +DELETE FROM files WHERE file_build_id = ? diff --git a/store/datastore/sql/sqlite/files/procs.sql b/store/datastore/sql/sqlite/files/procs.sql index a8643b3e7..5a9730aab 100644 --- a/store/datastore/sql/sqlite/files/procs.sql +++ b/store/datastore/sql/sqlite/files/procs.sql @@ -80,3 +80,7 @@ FROM procs WHERE proc_build_id = ? AND proc_ppid = ? AND proc_name = ? + +-- name: procs-delete-build + +DELETE FROM procs WHERE proc_build_id = ? diff --git a/store/datastore/sql/sqlite/sql_gen.go b/store/datastore/sql/sqlite/sql_gen.go index edbc4b2a9..8e2574797 100644 --- a/store/datastore/sql/sqlite/sql_gen.go +++ b/store/datastore/sql/sqlite/sql_gen.go @@ -9,10 +9,12 @@ var index = map[string]string{ "files-find-build": filesFindBuild, "files-find-proc-name": filesFindProcName, "files-find-proc-name-data": filesFindProcNameData, + "files-delete-build": filesDeleteBuild, "procs-find-id": procsFindId, "procs-find-build": procsFindBuild, "procs-find-build-pid": procsFindBuildPid, "procs-find-build-ppid": procsFindBuildPpid, + "procs-delete-build": procsDeleteBuild, } var filesFindBuild = ` @@ -57,6 +59,10 @@ WHERE file_proc_id = ? AND file_name = ? ` +var filesDeleteBuild = ` +DELETE FROM files WHERE file_build_id = ? +` + var procsFindId = ` SELECT proc_id @@ -139,3 +145,7 @@ WHERE proc_build_id = ? AND proc_ppid = ? AND proc_name = ? ` + +var procsDeleteBuild = ` +DELETE FROM procs WHERE proc_build_id = ? +` diff --git a/store/store.go b/store/store.go index 1dfa9935c..79abc787e 100644 --- a/store/store.go +++ b/store/store.go @@ -151,6 +151,7 @@ type Store interface { ProcList(*model.Build) ([]*model.Proc, error) ProcCreate([]*model.Proc) error ProcUpdate(*model.Proc) error + ProcClear(*model.Build) error LogFind(*model.Proc) (io.ReadCloser, error) LogSave(*model.Proc, io.Reader) error