123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- package service
- import (
- "bufio"
- "encoding/json"
- "errors"
- "fmt"
- "gadmin/config"
- "gadmin/internal/admin/consts"
- "gadmin/internal/admin/forms"
- "gadmin/internal/admin/library/docker"
- "gadmin/internal/admin/ws"
- "gadmin/internal/gorm/model"
- "gadmin/internal/gorm/query"
- "gadmin/utility"
- "gadmin/utility/character"
- "gadmin/utility/serializer"
- "gadmin/utility/token"
- "os"
- "strconv"
- "strings"
- "time"
- "github.com/docker/docker/api/types"
- "github.com/gin-gonic/gin"
- "github.com/sirupsen/logrus"
- "gorm.io/gorm"
- )
- var Deploy = new(sDeploy)
- type sDeploy struct{}
- // 一个容器部署完成后的消息上报
- func (s *sDeploy) Notify(ctx *gin.Context, req forms.DeployNotifyReq) serializer.Response {
- var (
- q = query.Use(config.DB).ServerDeploy
- ql = query.Use(config.DB).ServerDeployLog
- qs = query.Use(config.DB).ServerDeployStat
- stat *model.ServerDeployStat
- err error
- status = consts.DeployStatusSuc
- )
- // 本次部署针对的容器 及相关配置
- taskItem, err := ql.Where(ql.TraceID.Eq(req.TraceID)).First()
- if err != nil {
- logrus.Warnf("first err:%+v", err)
- return serializer.DBErr(err.Error(), err)
- }
- if taskItem == nil {
- return serializer.DBErr("操作记录不存在", nil)
- }
- // 取出容器配置
- deploy, err := q.Where(q.ID.Eq(taskItem.DeployID)).First()
- if err != nil {
- logrus.Warnf("deploy err:%+v", err)
- return serializer.DBErr(err.Error(), err)
- }
- if deploy == nil {
- return serializer.DBErr("服务器不存在", nil)
- }
- // 取本次部署统计信息 一次部署可能是多个容器
- if taskItem.PublishType == consts.DeployPublishTypeVersion {
- stat, err = qs.Where(qs.BatchID.Eq(taskItem.BatchID)).First()
- if err != nil {
- logrus.Warnf("stat err:%+v", err)
- return serializer.DBErr(err.Error(), err)
- }
- if stat == nil {
- return serializer.DBErr("批量记录不存在", nil)
- }
- // 解析一个容器上报数据
- parsingError := func(log *forms.DeployLogViewModel) {
- if log == nil {
- return
- }
- logrus.Warnf("parsingError log:%+v\n", log)
- if strings.Contains(log.LogContent, `level=error`) {
- req.Code = 1
- req.Msg = fmt.Sprintf("拉取json配置异常,请检查")
- return
- }
- // 提取本次启动的进程
- ProcessFlag := "要开始的进程内容:"
- line, err1 := extractFromFlagToEnd(log.LogContent, ProcessFlag)
- if err1 != nil {
- req.Code = 1
- req.Msg = fmt.Sprintf("未找到本次需要启动的进程信息,请检查")
- return
- }
- logrus.Infof("本次启动进程: %v\n", line)
- extra := make(map[string]interface{})
- err := json.Unmarshal([]byte(taskItem.Extra), &extra)
- if err != nil {
- logrus.Infof("parsingError 1: %v\n", err)
- return
- }
- deployServer, ok := extra["deployServ"]
- if !ok {
- logrus.Infof("parsingError 2: %v\n", extra)
- return
- }
- var ds []string
- ds1, ok := deployServer.([]interface{})
- if !ok {
- logrus.Infof("parsingError 3: %v %T\n", deployServer, deployServer)
- return
- }
- for _, v := range ds1 {
- ds = append(ds, v.(string))
- }
- // err = json.Unmarshal([]byte(ds1), &ds)
- // if err != nil {
- // logrus.Infof("parsingError 32: %v\n", err)
- // return
- // }
- logrus.Infof("parsingError 4: %v\n", ds)
- // 检查进程数量是否正常
- var monitor = make(map[string]bool)
- // _, startServ, _ := docker.ParseDeployServArgs(deploy.ServerType, ds, deploy.IsMproom)
- var serverList []string
- if len(ds) == 1 && ds[0] == "all" {
- serverList = strings.Split(line, ",")
- } else {
- serverList = ds
- }
- for _, v := range serverList {
- if v == consts.DeployPackJsonConvert {
- continue
- }
- // if v == consts.DeployPackMPRoom {
- // if deploy.IsMproom != consts.INTTRUE {
- // continue
- // }
- // }
- n := "./" + v
- monitor[n] = false
- }
- // if consts.DeployTypeGrave == deploy.ServerType {
- // if deploy.IsMproom == consts.INTTRUE {
- // monitor = map[string]bool{
- // "./archive": false,
- // // "./chapter": false,
- // "./chapterd": false,
- // //"./gate": false,
- // "./store": false,
- // "./world": false,
- // "./mproom": false,
- // }
- // } else {
- // monitor = map[string]bool{
- // "./archive": false,
- // // "./chapter": false,
- // "./chapterd": false,
- // "./store": false,
- // "./world": false,
- // }
- // }
- // }
- // if consts.DeployTypeLogin == deploy.ServerType {
- // monitor = map[string]bool{
- // "./login": false,
- // }
- // }
- // if consts.DeployTypeGate == deploy.ServerType {
- // monitor = map[string]bool{
- // "./gate": false,
- // }
- // }
- logrus.Infof("parsingError 5: %v\n", monitor)
- if len(monitor) == 0 {
- logrus.Warn("GameAlarm monitor is not set")
- return
- }
- process, err := docker.GetGraveProcess(docker.GraveProcessInput{Ctx: ctx, Deploy: deploy})
- if err != nil {
- req.Code = 2
- req.Msg = fmt.Sprintf("docker通讯异常:[%v]", err.Error())
- return
- }
- logrus.Infof("parsingError 7: %v\n", string(process))
- for _, line := range strings.Split(string(process), "\n") {
- // logrus.Infof("line:%s\n", line)
- awk := strings.Split(line, " ")
- awk2 := awk[len(awk)-1]
- if _, ok := monitor[awk2]; ok {
- monitor[awk2] = true
- }
- }
- logrus.WithField("method", "Notify").Infof("monitor: %+v\n", monitor)
- for s, b := range monitor {
- if !b {
- ps := strings.ReplaceAll(s, "./", "")
- req.Code = 2
- req.Msg = fmt.Sprintf("服务启动异常,未监测进程到:[%v]", ps)
- return
- }
- }
- }
- // 解析日志中是否存在错误
- log, err := s.getDeployLog(ctx, forms.DeployLogViewReq{Id: taskItem.ID, LogFile: req.LogFile})
- if err != nil {
- logrus.Warnf("解析日志失败:%+v", err.Error())
- }
- parsingError(log)
- }
- if req.Code != 0 {
- status = consts.DeployStatusErr
- }
- _, err = query.Use(config.DB).ServerDeploy.WithContext(ctx).Where(q.ID.Eq(taskItem.DeployID)).Updates(model.ServerDeploy{
- DeployStatus: status,
- })
- if err != nil {
- logrus.Warnf("Updates ServerDeploy err:%+v", err)
- return serializer.DBErr(err.Error(), err)
- }
- _, err = query.Use(config.DB).ServerDeployLog.WithContext(ctx).Where(ql.ID.Eq(taskItem.ID)).Updates(model.ServerDeployLog{
- LogFile: req.LogFile,
- ErrorMsg: req.Msg,
- Status: status,
- EndAt: time.Now(),
- })
- if err != nil {
- logrus.Warnf("Updates ServerDeployLog err:%+v", err)
- return serializer.DBErr(err.Error(), err)
- }
- msg := fmt.Sprintf("应用[%v]部署成功。远程服务器提示:%v", taskItem.Name, req.Msg)
- code := consts.CodeSuccess
- if req.Code != 0 {
- msg = fmt.Sprintf("应用[%v]部署失败。远程服务器提示:%v", taskItem.Name, req.Msg)
- code = consts.CodeParamErr
- }
- if taskItem.AdminID > 0 {
- msgData := ws.Msg{
- Id: taskItem.ID,
- Type: consts.SocketDeployNotify,
- Code: code,
- Msg: msg,
- }
- go ws.SendToAdmin(taskItem.AdminID, msgData)
- }
- if taskItem.PublishType != consts.DeployPublishTypeVersion {
- return serializer.Suc(nil)
- }
- // 更新统计
- if req.Code != 0 {
- tx := config.DB.Exec("UPDATE server_deploy_stat SET fail=fail+? WHERE batch_id=?", 1, stat.BatchID)
- if tx.Error != nil {
- logrus.Warnf("Notify Updates server_deploy_stat fail err:%+v", err)
- }
- stat.Fail += 1
- } else {
- tx := config.DB.Exec("UPDATE server_deploy_stat SET success=success+? WHERE batch_id=?", 1, stat.BatchID)
- if tx.Error != nil {
- logrus.Warnf("Notify Updates server_deploy_stat success err:%+v", err)
- }
- stat.Success += 1
- }
- // 满足通知条件
- if stat.Success+stat.Fail+stat.Timeout >= stat.Total {
- msgData := ws.Msg{
- Id: taskItem.ID,
- Type: consts.SocketDeployNotify,
- Code: consts.CodeSuccess,
- Msg: fmt.Sprintf("批量部署任务全部执行完毕,成功:%v,失败:%v,超时:%v", stat.Success, stat.Fail, stat.Timeout),
- }
- go ws.SendToAdmin(taskItem.AdminID, msgData)
- // 更新通知状态
- _, err = query.Use(config.DB).ServerDeployStat.WithContext(ctx).Where(qs.ID.Eq(stat.ID)).Updates(model.ServerDeployStat{
- IsNotify: consts.DeployNotifyOk,
- NotifyAt: time.Now(),
- })
- if err != nil {
- logrus.Warnf("Updates ServerDeployStat err:%+v", err)
- return serializer.DBErr(err.Error(), err)
- }
- }
- return serializer.Suc(nil)
- }
- func extractFromFlagToEnd(input string, startFlag string) (string, error) {
- // 使用bufio.NewScanner模拟逐行读取
- scanner := bufio.NewScanner(strings.NewReader(input))
- var line string
- found := false
- for scanner.Scan() {
- line = scanner.Text()
- if strings.Contains(line, startFlag) {
- // 找到标记,提取整行
- found = true
- break
- }
- }
- if err := scanner.Err(); err != nil {
- return "", err
- }
- if !found {
- return "", fmt.Errorf("startFlag not found")
- }
- startIndex := strings.Index(line, startFlag)
- if startIndex == -1 {
- return "", errors.New("未找到指定的字符串")
- }
- // 计算截取的开始位置(即"要开始的进程内容:"之后的位置)
- // 注意:由于我们要跳过"要开始的进程内容:"这个字符串,所以需要加上它的长度
- start := startIndex + len(startFlag)
- // 截取字符串
- // 这里我们没有指定end,所以它会截取到originalString的末尾
- result := line[start:]
- return result, nil
- }
- func (s *sDeploy) getDeployLog(ctx *gin.Context, req forms.DeployLogViewReq) (taskItem *forms.DeployLogViewModel, err error) {
- var (
- q = query.Use(config.DB).ServerDeploy
- ql = query.Use(config.DB).ServerDeployLog
- )
- if err = ql.Where(ql.ID.Eq(req.Id)).Scan(&taskItem); err != nil {
- return
- }
- if taskItem == nil {
- err = errors.New("操作记录不存在")
- return
- }
- deploy, err := q.Where(q.ID.Eq(taskItem.DeployID)).First()
- if err != nil {
- return
- }
- if deploy == nil {
- err = errors.New("操作记录不存在")
- return
- }
- if taskItem.LogFile == "" && req.LogFile != "" {
- taskItem.LogFile = req.LogFile
- }
- log, err := docker.ReadDeployLog(docker.ReadDeployLogInput{
- Ctx: ctx,
- Deploy: deploy,
- LogFile: taskItem.LogFile,
- })
- if err != nil {
- return
- }
- taskItem.LogContent = string(log)
- taskItem.LogContent = utility.Rmu0000(taskItem.LogContent)
- taskItem.LogContent = strings.Replace(taskItem.LogContent, ``, "", -1)
- taskItem.LogContent = strings.Replace(taskItem.LogContent, `[36mINFO[0m`, "", -1)
- return
- }
- func (s *sDeploy) LogView(ctx *gin.Context, req forms.DeployLogViewReq) serializer.Response {
- taskItem, err := s.getDeployLog(ctx, req)
- if err != nil {
- return serializer.ParamErr(err.Error(), err)
- }
- return serializer.Suc(taskItem)
- }
- func (s *sDeploy) LogList(ctx *gin.Context, req forms.DeployLogListReq) serializer.Response {
- var (
- q = query.Use(config.DB).ServerDeployLog
- m = q.WithContext(ctx).Where(q.DeployID.Eq(req.DeployId))
- offset int64 = 0
- models forms.UserAccountListRes
- lists []forms.DeployLogListModel
- )
- m = m.Order(q.ID.Desc())
- req.Page, req.PerPage, offset = forms.CalculatePage(req.Page, req.PerPage)
- count, err := m.Count()
- if err != nil {
- return serializer.Err(consts.CodeParamErr, "查询出错 count", err)
- }
- if count > 0 {
- if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&lists); err != nil {
- return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
- }
- }
- for k, v := range lists {
- if v.AdminID > 0 {
- user, err := User.GetUser(v.AdminID)
- if err != nil {
- logrus.Warnf("Deploy LogList GetUser err:%+v", err)
- continue
- }
- if user != nil {
- lists[k].AdminName = fmt.Sprintf("%v(%v)", user.UserName, v.AdminID)
- }
- }
- }
- models.List = lists
- models.Page = req.Page
- models.PerPage = req.PerPage
- models.PageCount = (count + req.PerPage - 1) / req.PerPage
- return serializer.Suc(models)
- }
- // 获取部署的服务器列表
- func (s *sDeploy) List(ctx *gin.Context, req forms.DeployListReq) serializer.Response {
- var (
- q = query.Use(config.DB).ServerDeploy
- m = q.WithContext(ctx).Where(q.Environment.Eq(os.Getenv("GIN_MODE")))
- offset int64 = 0
- models forms.UserAccountListRes
- lists []forms.DeployListData
- )
- if req.Name != "" {
- m = m.Where(q.Name.Like(req.Name))
- }
- if req.ContainerName != "" {
- m = m.Where(q.ContainerName.Like(req.ContainerName))
- }
- if len(req.ServerType) > 0 {
- m = m.Where(q.ServerType.In(req.ServerType...))
- }
- m = m.Order(q.ServerType, q.ID.Desc())
- req.Page, req.PerPage, offset = forms.CalculatePage(req.Page, req.PerPage)
- count, err := m.Count()
- if err != nil {
- return serializer.Err(consts.CodeParamErr, "查询出错 count", err)
- }
- if count > 0 {
- //if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&lists); err != nil {
- if err = m.Scan(&lists); err != nil {
- return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
- }
- }
- //区分多少docker地址
- dockerMap := make(map[string]map[string]string)
- for _, item := range lists {
- if _, ok := dockerMap[item.DockerAddr]; ok {
- continue
- }
- dockerInfoMap := make(map[string]string)
- dockerInfoMap["addr"] = item.DockerAddr
- dockerInfoMap["caPem"] = item.CaPem
- dockerInfoMap["certPem"] = item.CertPem
- dockerInfoMap["keyPem"] = item.KeyPem
- dockerMap[item.DockerAddr] = dockerInfoMap
- }
- logrus.Infof("dockerMap:%+v", dockerMap)
- //获取docker列表
- containerMap := make(map[string]types.Container)
- for addr, info := range dockerMap {
- logrus.Infof("info:%+v", info)
- containerList, err := docker.GetContainerList(ctx, info["addr"], info["caPem"], info["certPem"], info["keyPem"])
- if err != nil {
- logrus.Errorf("获取%s docker列表失败:%v", addr, err)
- // return serializer.Response{}
- }
- for _, item := range containerList {
- containerMap[item.Names[0]] = item
- }
- }
- nt := time.Now()
- for k, v := range lists {
- if v.AdminID > 0 {
- user, err := User.GetUser(v.AdminID)
- if err != nil {
- logrus.Warnf("Deploy LogList GetUser err:%+v", err)
- continue
- }
- if user != nil {
- lists[k].AdminName = fmt.Sprintf("%v(%v)", user.UserName, v.AdminID)
- }
- }
- if v.LastSyncAt.Add(consts.DeployRunSyncTime).Before(nt) {
- runStatus := consts.DeployRunStart
- container := containerMap["/"+v.ContainerName]
- if container.State != "running" {
- runStatus = consts.DeployRunStop
- }
- if container.ID == "" {
- runStatus = consts.DeployRunNoFound
- }
- _, err = query.Use(config.DB).ServerDeploy.WithContext(ctx).Where(q.ID.Eq(v.ID)).Updates(model.ServerDeploy{
- RunStatus: runStatus,
- LastSyncAt: time.Now(),
- })
- if err != nil {
- logrus.Warnf("ServerDeploy Updates LastSyncAt err:%+v", err)
- }
- }
- lists[k].DeployStatus = s.getLastDeployStatus(ctx, v.ID)
- }
- //for k, v := range lists {
- // if v.AdminID > 0 {
- // user, err := User.GetUser(v.AdminID)
- // if err != nil {
- // logrus.Warnf("Deploy LogList GetUser err:%+v", err)
- // continue
- // }
- // if user != nil {
- // lists[k].AdminName = fmt.Sprintf("%v(%v)", user.UserName, v.AdminID)
- // }
- // }
- // if v.LastSyncAt.Add(consts.DeployRunSyncTime).Before(nt) {
- // runStatus := consts.DeployRunStart
- // container, err := docker.GetContainer(ctx, v.DockerAddr, v.CaPem, v.CertPem, v.KeyPem, v.ContainerName)
- // if err != nil {
- // logrus.Warnf("ContainerErr: %+v", err)
- // }
- //
- // if container != nil {
- // if container.State != "running" {
- // runStatus = consts.DeployRunStop
- // }
- // } else {
- // runStatus = consts.DeployRunNoFound
- // logrus.Warnf("ContainerInfo: %+v;\n", container)
- // }
- //
- // _, err = query.Use(config.DB).ServerDeploy.WithContext(ctx).Where(q.ID.Eq(v.ID)).Updates(model.ServerDeploy{
- // RunStatus: runStatus,
- // LastSyncAt: time.Now(),
- // })
- //
- // if err != nil {
- // logrus.Warnf("ServerDeploy Updates LastSyncAt err:%+v", err)
- // }
- //
- // }
- //
- // lists[k].DeployStatus = s.getLastDeployStatus(ctx, v.ID)
- //}
- newList1 := make([]forms.DeployListData, 0)
- if len(req.RunStatus) > 0 {
- for _, item := range lists {
- if character.InSlice(req.RunStatus, strconv.Itoa(int(item.RunStatus))) {
- newList1 = append(newList1, item)
- }
- }
- } else {
- newList1 = lists
- }
- newList2 := make([]forms.DeployListData, 0)
- if len(req.DeployStatus) > 0 {
- for _, item := range newList1 {
- if character.InSlice(req.DeployStatus, strconv.Itoa(int(item.DeployStatus))) {
- newList2 = append(newList2, item)
- }
- }
- } else {
- newList2 = newList1
- }
- pageCount := int64(len(newList2))
- pageList := make([]forms.DeployListData, 0)
- if offset+req.PerPage <= pageCount-1 {
- pageList = newList2[offset : req.PerPage+offset]
- } else if offset+req.PerPage > pageCount-1 && offset <= pageCount-1 {
- pageList = newList2[offset:]
- }
- models.List = pageList
- //models.List = lists
- models.Page = req.Page
- models.PerPage = req.PerPage
- // todo 分页逻辑处理
- models.PageCount = (pageCount + req.PerPage - 1) / req.PerPage
- return serializer.Suc(models)
- }
- // getLastDeployStatus 获取最后的部署状态
- func (s *sDeploy) getLastDeployStatus(ctx *gin.Context, deployId int64) int32 {
- var ql = query.Use(config.DB).ServerDeployLog
- log, _ := ql.WithContext(ctx).Where(ql.DeployID.Eq(deployId)).Order(ql.ID.Desc()).First()
- if log == nil {
- return consts.DeployStatusWait
- }
- return log.Status
- }
- // 下发一键重启等部署任务
- func (s *sDeploy) Task(ctx *gin.Context, req forms.DeployTaskReq) serializer.Response {
- var (
- batchId = character.Md5Content([]byte(character.RandStringRunes(32)))
- taskList = make(map[string]docker.PushDeployTaskInput, len(req.Ids))
- )
- err := config.DB.Transaction(func(tx *gorm.DB) error {
- for _, id := range req.Ids {
- var (
- q = query.Use(config.DB).ServerDeploy
- ql = query.Use(config.DB).ServerDeployLog
- err error
- )
- first, err := q.Where(q.ID.Eq(id)).First()
- if err != nil {
- return err
- }
- if first == nil {
- return errors.New(fmt.Sprintf("服务器不存在 id:%v", id))
- }
- log, _ := ql.Where(ql.DeployID.Eq(first.ID)).Order(ql.CreatedAt.Desc()).First()
- // 只要正式服验证时间
- if os.Getenv("GIN_MODE") == "release" && log != nil && log.CreatedAt.Unix()+30 > time.Now().Unix() {
- return errors.New(fmt.Sprintf("距离上次部署时间过近,请稍后%v秒后再试 id:%v", log.CreatedAt.Unix()+30-time.Now().Unix(), id))
- }
- extra := make(map[string]interface{})
- extra["deployServ"] = req.DeployServ
- strExtra, err := json.Marshal(extra)
- if err != nil {
- return err
- }
- // 新建部署任务记录
- createData := &model.ServerDeployLog{
- AdminID: token.GetUID(ctx),
- DeployID: first.ID,
- BatchID: batchId,
- TraceID: character.Md5Content([]byte(character.RandStringRunes(32))),
- ContainerName: first.ContainerName,
- Name: first.Name,
- PublishType: consts.DeployPublishTypeVersion,
- Version: req.Version,
- Extra: string(strExtra),
- LogFile: "",
- Status: consts.DeployStatusIng,
- EndAt: time.Now().AddDate(-20, 0, 0),
- CreatedAt: time.Now(),
- }
- if err = query.Use(config.DB).ServerDeployLog.WithContext(ctx).Create(createData); err != nil {
- return err
- }
- if createData.ID < 1 {
- return errors.New(fmt.Sprintf("创建失败,请稍后重试! id:%v", id))
- }
- logrus.Warnf("DeployTask createData:%+v", createData)
- taskList[createData.TraceID] = docker.PushDeployTaskInput{
- Ctx: ctx,
- Deploy: first,
- Log: createData,
- DeployServ: req.DeployServ,
- }
- }
- // 插入批量记录
- if err := query.Use(config.DB).ServerDeployStat.WithContext(ctx).Create(&model.ServerDeployStat{
- AdminID: token.GetUID(ctx),
- BatchID: batchId,
- Total: int64(len(req.Ids)),
- Success: 0,
- Fail: 0,
- Timeout: 0,
- NotifyAt: time.Now().AddDate(-20, 0, 0),
- IsNotify: consts.DeployNotifyNo,
- CreatedAt: time.Now(),
- }); err != nil {
- return err
- }
- return nil
- })
- if err != nil {
- return serializer.DBErr(err.Error(), err)
- }
- for _, task := range taskList {
- err = docker.PushDeployTask(task)
- if err != nil {
- logrus.Infof("task.PushDeployTask return err:%+v", err)
- var (
- q = query.Use(config.DB).ServerDeploy
- ql = query.Use(config.DB).ServerDeployLog
- )
- _, err = query.Use(config.DB).ServerDeploy.WithContext(ctx).Where(q.ID.Eq(task.Deploy.ID)).Updates(model.ServerDeploy{
- RunStatus: consts.DeployStatusErr,
- LastSyncAt: time.Now(),
- })
- if err != nil {
- logrus.Warnf("task.ServerDeploy Updates LastSyncAt err:%+v", err)
- }
- errorMsg := fmt.Sprintf("创建远程任务失败:%v ", err.Error())
- _, err = query.Use(config.DB).ServerDeployLog.WithContext(ctx).Where(ql.ID.Eq(task.Log.ID)).Updates(model.ServerDeployLog{
- ErrorMsg: errorMsg,
- Status: consts.DeployStatusErr,
- EndAt: time.Now(),
- })
- if err != nil {
- logrus.Warnf("task.ServerDeployLog Updates LastSyncAt err:%+v", err)
- }
- tx := config.DB.Exec("UPDATE server_deploy_stat SET fail=fail+? WHERE batch_id=?", 1, batchId)
- if tx.Error != nil {
- logrus.Warnf("task.ServerDeployLog Updates server_deploy_stat err:%+v", err)
- }
- // 推送失败通知
- if task.Log.AdminID > 0 {
- msgData := ws.Msg{
- Id: task.Deploy.ID,
- Type: consts.SocketDeployNotify,
- Code: consts.CodeParamErr,
- Msg: fmt.Sprintf("应用[%v]部署失败。远程服务器提示:%v", task.Deploy.Name, errorMsg),
- }
- go ws.SendToAdmin(task.Log.AdminID, msgData)
- }
- }
- }
- return serializer.Suc(nil)
- }
- func (s *sDeploy) Stop(ctx *gin.Context, req forms.DeployStopReq) serializer.Response {
- for _, id := range req.Ids {
- var (
- q = query.Use(config.DB).ServerDeploy
- ql = query.Use(config.DB).ServerDeployLog
- err error
- )
- first, err := q.Where(q.ID.Eq(id)).First()
- if err != nil {
- return serializer.DBErr(err.Error(), err)
- }
- if first == nil {
- return serializer.DBErr(fmt.Sprintf("Stop 服务器不存在 id:%v", id), nil)
- }
- log, _ := ql.Where(ql.DeployID.Eq(first.ID)).Order(ql.CreatedAt.Desc()).First()
- if log != nil && log.CreatedAt.Unix()+30 > time.Now().Unix() {
- return serializer.DBErr(fmt.Sprintf("Stop 距离上次部署时间过近,请稍后%v秒后再试 id:%v", log.CreatedAt.Unix()+30-time.Now().Unix(), id), nil)
- }
- // 新建部署任务记录
- createData := &model.ServerDeployLog{
- AdminID: token.GetUID(ctx),
- DeployID: first.ID,
- TraceID: character.Md5Content([]byte(character.RandStringRunes(32))),
- ContainerName: first.ContainerName,
- Name: first.Name,
- PublishType: consts.DeployPublishTypeStop,
- Extra: fmt.Sprintf(`{"stopType":%v}`, req.StopType),
- LogFile: "",
- Status: consts.DeployStatusIng,
- EndAt: time.Now(),
- CreatedAt: time.Now(),
- }
- if err = query.Use(config.DB).ServerDeployLog.WithContext(ctx).Create(createData); err != nil {
- return serializer.DBErr(err.Error(), err)
- }
- if createData.ID < 1 {
- return serializer.ParamErr(fmt.Sprintf("Stop 创建失败,请稍后重试! id:%v", id), nil)
- }
- err = docker.PushDeployStop(docker.PushDeployStopInput{
- Ctx: ctx,
- Deploy: first,
- Log: createData,
- StopType: req.StopType,
- })
- if err != nil {
- return serializer.ParamErr(fmt.Sprintf("Stop 创建远程任务失败:%v id:%v", err.Error(), id), nil)
- }
- }
- return serializer.Suc(nil)
- }
- // 编辑某服的配置
- func (s *sDeploy) Edit(ctx *gin.Context, req forms.DeployEditReq) serializer.Response {
- var (
- q = query.Use(config.DB).ServerDeploy
- err error
- )
- // 编辑
- if req.ID > 0 {
- _, err = query.Use(config.DB).ServerDeploy.WithContext(ctx).Where(q.ID.Eq(req.ID)).Updates(model.ServerDeploy{
- GroupID: req.GroupID,
- ServerType: req.ServerType,
- ContainerName: req.ContainerName,
- Name: req.Name,
- DockerAddr: req.DockerAddr,
- CaPem: req.CaPem,
- CertPem: req.CertPem,
- KeyPem: req.KeyPem,
- Remark: req.Remark,
- IsMproom: req.IsMproom,
- LastSyncAt: time.Time{},
- CreatedAt: time.Now(),
- })
- if err != nil {
- return serializer.DBErr(err.Error(), err)
- }
- return serializer.Suc(nil)
- }
- // 新增
- createData := model.ServerDeploy{
- Environment: os.Getenv("GIN_MODE"),
- AdminID: token.GetUID(ctx),
- GroupID: req.GroupID,
- ContainerName: req.ContainerName,
- Name: req.Name,
- ServerType: req.ServerType,
- DockerAddr: req.DockerAddr,
- CaPem: req.CaPem,
- CertPem: req.CertPem,
- KeyPem: req.KeyPem,
- Remark: req.Remark,
- RunStatus: consts.DeployRunStop,
- DeployStatus: consts.DeployStatusWait,
- CreatedAt: time.Now(),
- }
- if err = query.Use(config.DB).ServerDeploy.WithContext(ctx).Omit(q.LastSyncAt.Desc()).Create(&createData); err != nil {
- return serializer.DBErr(err.Error(), err)
- }
- if createData.ID < 1 {
- return serializer.ParamErr("创建失败,请稍后重试!", nil)
- }
- return serializer.Suc(nil)
- }
- func (s *sDeploy) Delete(ctx *gin.Context, req forms.DeployDeleteReq) serializer.Response {
- // 编辑
- if req.ID <= 0 {
- return serializer.ParamErr("ID不能空,删除失败!", nil)
- }
- if _, err := query.Use(config.DB).ServerDeploy.WithContext(ctx).Where(query.Use(config.DB).ServerDeploy.ID.Eq(req.ID)).Delete(); err != nil {
- return serializer.DBErr(err.Error(), err)
- }
- return serializer.Suc(nil)
- }
|