This commit is contained in:
ryanmao 2020-10-02 16:04:26 +08:00
parent d6f6993b98
commit 62b15a84cf
19 changed files with 373 additions and 47 deletions

View File

@ -40,7 +40,7 @@ const sqls = `
Target Server Version : 3030001
File Encoding : 65001
Date: 30/09/2020 20:03:44
Date: 02/10/2020 16:02:56
*/
PRAGMA foreign_keys = false;
@ -97,7 +97,9 @@ CREATE TABLE "t_model" (
"title" text,
"desc" text,
"times" datetime,
"del" integer DEFAULT 0
"del" integer DEFAULT 0,
"envs" text,
"wrkdir" text
);
-- ----------------------------
@ -116,7 +118,8 @@ CREATE TABLE "t_model_run" (
"tid" integer,
"times" datetime,
"timesd" datetime,
"state" integer
"state" integer,
"errs" text
);
-- ----------------------------
@ -156,7 +159,8 @@ CREATE TABLE "t_plugin" (
"cont" text,
"times" datetime,
"sort" integer DEFAULT 100,
"del" integer DEFAULT 0
"del" integer DEFAULT 0,
"exend" integer DEFAULT 0
);
-- ----------------------------

View File

@ -10,4 +10,6 @@ var (
Path string
Gin *gin.Engine
Db *xorm.Engine
RunTaskLen int = 5
)

Binary file not shown.

View File

@ -10,7 +10,7 @@
Target Server Version : 3030001
File Encoding : 65001
Date: 30/09/2020 20:03:44
Date: 02/10/2020 16:02:56
*/
PRAGMA foreign_keys = false;
@ -67,7 +67,9 @@ CREATE TABLE "t_model" (
"title" text,
"desc" text,
"times" datetime,
"del" integer DEFAULT 0
"del" integer DEFAULT 0,
"envs" text,
"wrkdir" text
);
-- ----------------------------
@ -86,7 +88,8 @@ CREATE TABLE "t_model_run" (
"tid" integer,
"times" datetime,
"timesd" datetime,
"state" integer
"state" integer,
"errs" text
);
-- ----------------------------
@ -126,7 +129,8 @@ CREATE TABLE "t_plugin" (
"cont" text,
"times" datetime,
"sort" integer DEFAULT 100,
"del" integer DEFAULT 0
"del" integer DEFAULT 0,
"exend" integer DEFAULT 0
);
-- ----------------------------

10
main.go
View File

@ -3,6 +3,7 @@ package main
import (
"gokins/comm"
"gokins/core"
"gokins/mgr"
"gokins/route"
"gokins/service/dbService"
"net/http"
@ -10,7 +11,6 @@ import (
"path/filepath"
"github.com/gin-gonic/gin"
ruisUtil "github.com/mgr9525/go-ruisutil"
)
func init() {
@ -64,15 +64,11 @@ func main() {
dbService.SetParam("jwt-key", jwtKey)
}
core.JwtKey = jkey
comm.Gin.Any("/test", func(c *gin.Context) {
data := ruisUtil.NewMap()
data.Set("cont", "你好啊world!")
//utils.html(c, "test.html", data)
c.HTML(200, "test.html", data)
})
route.Init()
mgr.ExecMgr.Start()
err = comm.Gin.Run(":8030")
if err != nil {
println("gin run err:" + err.Error())
}
mgr.Cancel()
}

87
mgr/exec.go Normal file
View File

@ -0,0 +1,87 @@
package mgr
import (
"gokins/comm"
"gokins/model"
"sync"
"time"
ruisUtil "github.com/mgr9525/go-ruisutil"
)
var ExecMgr = &execManager{}
type execManager struct {
tm time.Time
lk sync.Mutex
tasks map[int]*RunTask
}
func (c *execManager) Start() {
c.tasks = make(map[int]*RunTask)
go func() {
for {
select {
case <-mgrCtx.Done():
break
default:
c.run()
time.Sleep(time.Second)
}
}
}()
}
func (c *execManager) run() {
defer ruisUtil.Recovers("run", func(errs string) {
println("execManager run err:" + errs)
})
if time.Since(c.tm).Seconds() < 20 {
return
}
c.tm = time.Now()
c.lk.Lock()
defer c.lk.Unlock()
for k, v := range c.tasks {
if v.cncl == nil {
delete(c.tasks, k)
}
}
if len(c.tasks) >= comm.RunTaskLen {
return
}
var ls []*model.TModelRun
err := comm.Db.Where("state=0 or state=1").Find(&ls)
if err != nil {
println("execManager err:" + err.Error())
return
}
for _, v := range ls {
if v.State == 0 {
v.State = 1
comm.Db.Cols("state").Where("id=?", v.Id).Update(v)
}
_, ok := c.tasks[v.Id]
if !ok {
e := &RunTask{Mr: v}
c.tasks[v.Id] = e
e.start()
}
}
}
func (c *execManager) Refresh() {
c.tm = time.Time{}
}
func (c *execManager) StopTask(id int) {
c.lk.Lock()
defer c.lk.Unlock()
e, ok := c.tasks[id]
if ok {
e.stop()
}
//v := &model.TModelRun{}
//v.State = -1
//_, err := comm.Db.Cols("state").Where("id=?", v.Id).Update(v)
//return err
}

12
mgr/mgr.go Normal file
View File

@ -0,0 +1,12 @@
package mgr
import "context"
var (
mgrCtx context.Context
Cancel context.CancelFunc
)
func init() {
mgrCtx, Cancel = context.WithCancel(context.Background())
}

144
mgr/run.go Normal file
View File

@ -0,0 +1,144 @@
package mgr
import (
"bytes"
"context"
"errors"
"gokins/comm"
"gokins/model"
"gokins/service/dbService"
"os/exec"
"runtime"
"strings"
"time"
ruisIo "github.com/mgr9525/go-ruisutil/ruisio"
ruisUtil "github.com/mgr9525/go-ruisutil"
)
type RunTask struct {
Md *model.TModel
Mr *model.TModelRun
plugs []*model.TPlugin
ctx context.Context
cncl context.CancelFunc
stdout *bytes.Buffer
}
func (c *RunTask) start() {
if c.cncl != nil {
return
}
c.Md = dbService.GetModel(c.Mr.Tid)
if c.Md == nil {
return
}
c.ctx, c.cncl = context.WithCancel(context.Background())
go func() {
defer ruisUtil.Recovers("RunTask start", nil)
c.plugs = nil
err := comm.Db.Where("del!='1' and tid=?", c.Mr.Tid).OrderBy("sort ASC,id ASC").Find(&c.plugs)
if err != nil {
c.end(2, "db err:"+err.Error())
return
}
for _, v := range c.plugs {
select {
case <-c.ctx.Done():
c.end(-1, "手动停止")
return
default:
err := c.run(v)
if err != nil {
println("cmd run err:", err.Error())
c.end(2, err.Error())
return
}
time.Sleep(time.Second)
}
}
c.end(4, "")
}()
}
func (c *RunTask) run(pgn *model.TPlugin) (rterr error) {
defer ruisUtil.Recovers("RunTask.run", func(errs string) {
rterr = errors.New(errs)
})
rn := dbService.FindPluginRun(c.Mr.Tid, c.Mr.Id, pgn.Id)
if rn == nil {
rn = &model.TPluginRun{Mid: c.Mr.Tid, Tid: c.Mr.Id, Pid: pgn.Id}
rn.Times = time.Now()
rn.State = 1
_, err := comm.Db.Insert(rn)
if err != nil {
return err
}
}
if rn.State != 1 {
return nil
}
select {
case <-c.ctx.Done():
return nil
default:
}
name := "sh"
par0 := "-c"
if runtime.GOOS == "windows" {
name = "cmd"
par0 = "/c"
}
c.stdout = &bytes.Buffer{}
//var stderr bytes.Buffer
cmd := exec.CommandContext(c.ctx, name, par0, pgn.Cont)
cmd.Stdout = c.stdout
cmd.Stderr = c.stdout
if c.Md.Wrkdir != "" && ruisIo.PathExists(c.Md.Wrkdir) {
cmd.Dir = c.Md.Wrkdir
}
if c.Md.Envs != "" {
str := strings.ReplaceAll(c.Md.Envs, "\t", "")
envs := strings.Split(str, "\n")
cmd.Env = envs
}
err := cmd.Run()
rn.State = 4
if err != nil {
println("cmd.run err:" + err.Error())
rn.State = 2
}
if cmd.ProcessState != nil {
rn.Excode = cmd.ProcessState.ExitCode()
}
rn.Timesd = time.Now()
rn.Output = c.stdout.String()
_, err = comm.Db.Cols("state", "excode", "timesd", "output").Where("id=?", rn.Id).Update(rn)
if err != nil {
return err
}
if pgn.Exend == 1 && rn.Excode != 0 {
return errors.New("cmd exit err")
}
return nil
}
func (c *RunTask) end(stat int, errs string) {
c.stop()
v := &model.TModelRun{}
v.State = stat
v.Errs = errs
v.Timesd = time.Now()
_, err := comm.Db.Cols("state", "errs", "timesd").Where("id=?", c.Mr.Id).Update(v)
if err != nil {
println("db err:", err.Error())
}
}
func (c *RunTask) stop() {
if c.cncl != nil {
c.cncl()
c.cncl = nil
}
}

View File

@ -5,10 +5,22 @@ import (
)
type TModel struct {
Id int `xorm:"pk autoincr"`
Uid string
Title string
Desc string
Times time.Time
Del int
Id int `xorm:"pk autoincr"`
Uid string
Title string
Desc string
Times time.Time
Del int
Envs string
Wrkdir string
}
type TModelRun struct {
Id int `xorm:"pk autoincr"`
Tid int //model id
Uid string
Times time.Time
Timesd time.Time
State int //-1已停止0等待1运行2运行失败4运行成功
Errs string
}

View File

@ -1,14 +0,0 @@
package model
import (
"time"
)
type TModelRun struct {
Id int `xorm:"pk autoincr"`
Tid int
Uid string
Times time.Time
Timesd time.Time
State int
}

View File

@ -6,7 +6,7 @@ import (
type TPlugin struct {
Id int `xorm:"pk autoincr"`
Tid int
Tid int //model id
Type int
Title string
Para string
@ -14,4 +14,17 @@ type TPlugin struct {
Times time.Time
Sort int
Del int
Exend int
}
type TPluginRun struct {
Id int `xorm:"pk autoincr"`
Pid int //plugin id
Mid int //model id
Tid int //modelRun id
Times time.Time
Timesd time.Time
State int //-1已停止0等待1运行2运行失败4运行成功
Excode int
Output string
}

View File

@ -7,11 +7,13 @@ import (
)
type Model struct {
Id int `xorm:"pk autoincr"`
Uid string
Title string
Desc string
Times time.Time
Id int `xorm:"pk autoincr"`
Uid string
Title string
Desc string
Times time.Time
Envs string
Wrkdir string
}
func (Model) TableName() string {
@ -21,7 +23,7 @@ func (Model) TableName() string {
func (c *Model) Save() error {
var err error
if c.Id > 0 {
_, err = comm.Db.Cols("title", "desc").Where("id=?", c.Id).Update(c)
_, err = comm.Db.Cols("title", "desc", "envs", "wrkdir").Where("id=?", c.Id).Update(c)
} else {
c.Times = time.Now()
_, err = comm.Db.Insert(c)

View File

@ -16,6 +16,7 @@ type Plugin struct {
Cont string
Times time.Time
Sort int
Exend int
}
func (Plugin) TableName() string {
@ -25,7 +26,7 @@ func (Plugin) TableName() string {
func (c *Plugin) Save() error {
var err error
if c.Id > 0 {
_, err = comm.Db.Cols("type", "title", "para", "cont", "sort").Where("id=?", c.Id).Update(c)
_, err = comm.Db.Cols("type", "title", "para", "cont", "sort", "exend").Where("id=?", c.Id).Update(c)
} else {
if c.Tid <= 0 {
return errors.New("what?")

View File

@ -23,6 +23,7 @@ func Init() {
gpModel.Any("/del", core.GinHandler(server.ModelDel))
gpModel.Any("/runs", core.GinHandler(server.ModelRuns))
gpModel.Any("/run", core.GinHandler(server.ModelRun))
gpModel.Any("/stop", core.GinHandler(server.ModelStop))
gpPlug := comm.Gin.Group("/plug")
gpPlug.Use(utilService.MidNeedLogin)

View File

@ -4,6 +4,7 @@ import (
"fmt"
"gokins/comm"
"gokins/core"
"gokins/mgr"
"gokins/model"
"gokins/models"
"gokins/service/utilService"
@ -87,5 +88,15 @@ func ModelRun(c *gin.Context, req *ruisUtil.Map) {
c.String(500, "add err:"+err.Error())
return
}
mgr.ExecMgr.Refresh()
c.String(200, fmt.Sprintf("%d", m.Id))
}
func ModelStop(c *gin.Context, req *ruisUtil.Map) {
id, err := req.GetInt("id")
if err != nil || id <= 0 {
c.String(500, "param err")
return
}
mgr.ExecMgr.StopTask(int(id))
c.String(200, "ok")
}

View File

@ -0,0 +1,35 @@
package dbService
import (
"gokins/comm"
"gokins/model"
)
func GetPlugin(id int) *model.TPlugin {
if id <= 0 {
return nil
}
e := new(model.TPlugin)
ok, err := comm.Db.Where("id=?", id).Get(e)
if err != nil {
return nil
}
if ok {
return e
}
return nil
}
func FindPluginRun(mid, tid, pid int) *model.TPluginRun {
if mid <= 0 || tid <= 0 || pid <= 0 {
return nil
}
e := new(model.TPluginRun)
ok, err := comm.Db.Where("mid=? and tid=? and pid=?", mid, tid, pid).Get(e)
if err != nil {
return nil
}
if ok {
return e
}
return nil
}

View File

@ -2,12 +2,18 @@
<el-dialog title="流水线编辑" :visible.sync="formVisible" :close-on-click-modal="false">
<el-col :span="24" style="margin-bottom: 20px;">
<el-form :model="formData" label-width="80px" :rules="formRules" ref="formd">
<el-form-item label="任务名称" prop="Title">
<el-form-item label="项目名称" prop="Title">
<el-input v-model="formData.Title" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input type="textarea" v-model="formData.Desc" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="工作目录">
<el-input v-model="formData.Wrkdir" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="环境变量">
<el-input type="textarea" v-model="formData.Envs" auto-complete="off" :rows="8" placeholder="每行一个变量,格式name=xxxx"></el-input>
</el-form-item>
</el-form>
</el-col>
<!--工具条-->
@ -41,12 +47,16 @@
Id:'',
Title: '',
Desc: '',
Wrkdir:'',
Envs:''
}
if(e)
this.formData={
Id:e.Id,
Title: e.Title,
Desc: e.Desc,
Wrkdir:e.Wrkdir,
Envs:e.Envs
}
},/*handleSelect:function(id){
this.tmpltCont='';

View File

@ -15,6 +15,9 @@
<el-form-item label="排序" prop="Sort">
<el-input v-model="formData.Sort" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="执行失败">
<el-switch v-model="formData.exend" active-text="停止后续所有任务"></el-switch>
</el-form-item>
</el-form>
</el-col>
<!--工具条-->
@ -58,6 +61,7 @@
Para: '',
Cont: '',
Sort: '',
exend:true,
}
if(e)
this.formData={
@ -68,6 +72,7 @@
Para: e.Para,
Cont: e.Cont,
Sort: e.Sort,
exend:e.Exend==1
}
},/*handleSelect:function(id){
this.tmpltCont='';
@ -91,7 +96,8 @@
},*/formSubmit(){
this.$refs.formd.validate((valid) => {
if (valid) {
this.formLoading = true;
this.formLoading = true;
this.formData.Exend=this.formData.exend?1:2;
this.$post('/plug/edit',this.formData).then(res=>{
console.log(res);
this.$emit('submitOK');

View File

@ -26,8 +26,8 @@
<template slot-scope="{row}">
<span v-if="row.State==-1" style="color:red">已停止</span>
<span v-if="row.State==0" style="color:red">等待中</span>
<span v-if="row.State==1" style="color:green">运行中</span>
<span v-if="row.State==2" style="color:green">运行失败</span>
<span v-if="row.State==1" style="color:blue">运行中</span>
<span v-if="row.State==2" style="color:red">运行失败</span>
<span v-if="row.State==4" style="color:green">运行成功</span>
</template>
</el-table-column>