Compare commits

...

7 Commits

Author SHA1 Message Date
junleea baae696b56 Merge branch 'refs/heads/feature-cid' 2024-07-06 10:32:11 +08:00
junleea c3c4668c26 更新脚本 2024-07-06 10:32:05 +08:00
junleea 69a25507e8 修复修改及run问题 2024-07-05 16:55:57 +08:00
junleea 77b76caf39 后端cid部分基本完成,待测试 2024-07-05 11:38:59 +08:00
junleea f57d9ee392 添加日志查看及添加回调接口,脚本内容待拼接 2024-07-05 10:46:02 +08:00
junleea c4b96f9a9f 持续集成处理部分完成,修改表结构。 2024-07-05 10:28:05 +08:00
junleea 2501db94f5 添加持续集成部署部分数据库部分,handler大概框架 2024-07-04 18:31:04 +08:00
6 changed files with 334 additions and 2 deletions

View File

@ -1,6 +1,7 @@
#!/bin/bash
echo "Building the project"
source /etc/profile
cd /home/videoplayer
go build
git pull
pwd
/home/lijun/go/bin/go build
echo "Build complete"

102
dao/cid.go Normal file
View File

@ -0,0 +1,102 @@
package dao
import (
"fmt"
"gorm.io/gorm"
)
type CID struct {
gorm.Model
Auth_id int `gorm:"column:auth_id"`
Name string `gorm:"column:name"`
Url string `gorm:"column:url"`
Script string `gorm:"column:script"`
Token string `gorm:"column:token"` // 用于外部回调
}
type CIDRunLog struct {
gorm.Model
CID_id int `gorm:"column:cid_id"`
Auth_id int `form:"column:auth_id"`
Log string `gorm:"column:log"`
Error string `gorm:"column:error"`
}
// CreateCID 创建持续集成、部署
func CreateCID(name, url, script, token string, auth_id int) uint {
cid := CID{Name: name, Url: url, Script: script, Token: token, Auth_id: auth_id}
result := DB.Debug().Create(&cid)
if result.Error != nil {
return 0
}
return cid.ID
}
// DeleteCIDByID 删除持续集成、部署
func DeleteCIDByID(id, auth_id int) bool {
res := DB.Debug().Model(&CID{}).Where("id = ? and auth_id = ?", id, auth_id).Delete(&CID{})
if res.Error != nil {
return false
}
return true
}
// FindCIDByID 查找持续集成、部署
func FindCIDByID(id, auth_id int) CID {
var cid CID
DB.Debug().Where("id = ? and auth_id = ?", id, auth_id).First(&cid)
return cid
}
// FindCIDByAuthID 查找持续集成、部署
func FindCIDByAuthID(auth_id int) []CID {
var cids []CID
DB.Debug().Where("auth_id = ?", auth_id).Find(&cids)
return cids
}
// UpdateCIDByID 更新持续集成、部署
func UpdateCIDByID(id, auth_id int, name, url, script, token string) bool {
pd := FindCIDByID(id, auth_id)
if pd.ID == 0 {
return false
}
// 如果token为空则不更新token
if token == "" {
token = pd.Token
}
result := DB.Debug().Model(&CID{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(CID{Name: name, Url: url, Script: script, Token: token})
if result.Error != nil {
return false
}
return true
}
// CreateRunLog,添加执行日志
func CreateRunLog(cid_id, auth_id int, log, err string) uint {
cidRunLog := CIDRunLog{CID_id: cid_id, Auth_id: auth_id, Log: log, Error: err}
result := DB.Debug().Create(&cidRunLog)
if result != nil {
fmt.Println(err)
return 0
}
return cidRunLog.ID
}
func FindRunLogByAuthID(auth_id int) []CIDRunLog {
var cidRunLogs []CIDRunLog
DB.Debug().Where(" auth_id = ?", auth_id).Find(&cidRunLogs).Order("created_at desc")
return cidRunLogs
}
func FindRunLogByID(auth_id, cid_id int) CIDRunLog {
var cidRunLog CIDRunLog
DB.Debug().Where("cid_id = ? and auth_id = ?", cid_id, auth_id).First(&cidRunLog)
return cidRunLog
}
func FindCIDByIDAndToken(id int, token string) CID {
var cid CID
DB.Debug().Where("id = ? and token = ?", id, token).First(&cid)
return cid
}

View File

@ -32,6 +32,14 @@ func Init() {
if err != nil {
fmt.Println("logger table:", err)
} // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表
err = db.AutoMigrate(&CID{})
if err != nil {
fmt.Println("cid table:", err)
} // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表
err = db.AutoMigrate(&CIDRunLog{})
if err != nil {
fmt.Println("cidrunlog table:", err)
} // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表
DB = db
}

210
handler/cid.go Normal file
View File

@ -0,0 +1,210 @@
package handler
import (
"bytes"
"fmt"
"github.com/gin-gonic/gin"
"os/exec"
"regexp"
"strconv"
"videoplayer/dao"
"videoplayer/proto"
)
type CIDCreateReq struct {
Name string `json:"name" form:"name"`
Url string `json:"url" form:"url"`
Script string `json:"script" form:"script"`
}
type CIDDeleteReq struct {
ID int `json:"id" form:"id"`
}
type CIDRunReq struct {
ID int `json:"id" form:"id"`
}
type CIDUpdateReq struct {
ID int `json:"id" form:"id"`
Name string `json:"name" form:"name"`
Url string `json:"url" form:"url"`
Script string `json:"script" form:"script"`
Token string `json:"cidtoken" form:"cidtoken"`
}
func SetUpCIDGroup(router *gin.Engine) {
cidGroup := router.Group("/cid") //持续集成、部署
cidGroup.POST("/create", CreateCID)
cidGroup.POST("/delete", DeleteCID)
cidGroup.POST("/update", UpdateCID)
cidGroup.POST("/list", GetCIDList)
cidGroup.POST("/run", RunCID)
cidGroup.POST("/log", GetCIDLogList) //获取执行日志
cidGroup.POST("/log/detail", GetCIDLog) //获取执行日志详情
cidGroup.POST("/callback", CIDCallback)
}
func RunCID(c *gin.Context) {
var req CIDRunReq
if err := c.ShouldBind(&req); err == nil {
// 获取用户ID
id, _ := c.Get("id")
authID := int(id.(float64))
cid := dao.FindCIDByID(req.ID, authID)
if cid.ID == 0 {
c.JSON(200, gin.H{"error": "CID not found", "code": proto.OperationFailed, "message": "failed"})
return
} else {
re := regexp.MustCompile(`(?i)(?:https?://|git@)[^/]+/([^/]+)/([^/]+)(?:\.git)?$`)
matches := re.FindStringSubmatch(cid.Url)
name := matches[2]
scriptContent := `#!/bin/bash
TARGET_DIR = ` + proto.CID_BASE_DIR + `/workspace` + name + `
if [ ! -d $TARGET_DIR ]; then
git clone ` + cid.Url + `
cd $TARGET_DIR/` + name + `
else
cd $TARGET_DIR/` + name + `
git pull
fi
` + cid.Script
//执行脚本
cmd := exec.Command("/bin/bash", "-c", scriptContent)
err3 := cmd.Run()
fmt.Println("bash content:", scriptContent)
// 使用bytes.Buffer捕获输出
var out bytes.Buffer
cmd.Stdout = &out
dao.CreateRunLog(req.ID, authID, out.String(), err3.Error()) //添加执行日志
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
}
}
func CreateCID(c *gin.Context) {
var req CIDCreateReq
if err := c.ShouldBind(&req); err == nil {
// 获取用户ID
id, _ := c.Get("id")
authID := int(id.(float64))
token, _ := generateRandomHexString(32)
res := dao.CreateCID(req.Name, req.Url, req.Script, token, authID)
if res != 0 {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
} else {
c.JSON(200, gin.H{"error": "CreateCID failed", "code": proto.OperationFailed, "message": "failed"})
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
}
}
func DeleteCID(c *gin.Context) {
var req CIDDeleteReq
if err := c.ShouldBind(&req); err == nil {
// 获取用户ID
id, _ := c.Get("id")
authID := int(id.(float64))
cid := dao.DeleteCIDByID(req.ID, authID)
if cid == false {
c.JSON(200, gin.H{"error": "CID not found", "code": proto.OperationFailed, "message": "failed"})
return
} else {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
}
}
func UpdateCID(c *gin.Context) {
var req CIDUpdateReq
if err := c.ShouldBind(&req); err == nil {
// 获取用户ID
id, _ := c.Get("id")
authID := int(id.(float64))
cid := dao.UpdateCIDByID(req.ID, authID, req.Name, req.Url, req.Script, req.Token)
if cid == false {
c.JSON(200, gin.H{"error": "CID not found", "code": proto.OperationFailed, "message": "failed"})
return
} else {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
}
}
func GetCIDList(c *gin.Context) {
// 获取用户ID
id, _ := c.Get("id")
authID := int(id.(float64))
cids := dao.FindCIDByAuthID(authID)
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": cids})
}
func GetCIDLog(c *gin.Context) {
var req CIDRunReq
if err := c.ShouldBind(&req); err == nil {
// 获取用户ID
id, _ := c.Get("id")
authID := int(id.(float64))
cidLogs := dao.FindRunLogByID(req.ID, authID)
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": cidLogs})
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
}
}
func GetCIDLogList(c *gin.Context) {
// 获取用户ID
id, _ := c.Get("id")
authID := int(id.(float64))
cidLogs := dao.FindRunLogByAuthID(authID)
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": cidLogs})
}
func CIDCallback(c *gin.Context) {
// 获取用户ID
token := c.Query("token")
cid_id := c.Query("id")
//将cid转换为int
cid, _ := strconv.Atoi(cid_id)
if token == "" || cid == 0 {
c.JSON(200, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
res := dao.FindCIDByIDAndToken(cid, token)
if res.ID != 0 {
//从url获取仓库名称
re := regexp.MustCompile(`(?i)(?:https?://|git@)[^/]+/([^/]+)/([^/]+)(?:\.git)?$`)
matches := re.FindStringSubmatch(res.Url)
name := matches[2]
scriptContent := `#!/bin/bash
TARGET_DIR = ` + proto.CID_BASE_DIR + `/workspace` + name + `
if [ ! -d $TARGET_DIR ]; then
git clone ` + res.Url + `
cd $TARGET_DIR/` + name + `
else
cd $TARGET_DIR/` + name + `
git pull
fi
` + res.Script
//执行脚本
cmd := exec.Command("/bin/bash", "-c", scriptContent)
err3 := cmd.Run()
// 使用bytes.Buffer捕获输出
var out bytes.Buffer
cmd.Stdout = &out
dao.CreateRunLog(cid, res.Auth_id, out.String(), err3.Error()) //添加执行日志
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
} else {
c.JSON(200, gin.H{"error": "CID not found by id and token", "code": proto.OperationFailed, "message": "failed"})
return
}
}

View File

@ -4,6 +4,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"io"
"os"
"strings"
"videoplayer/dao"
"videoplayer/handler"
@ -24,10 +25,17 @@ func main() {
handler.SetUpUserGroup(r) // User
handler.SetUpDeviceGroup(r) // Device
handler.SetUpIMGroup(r) // IM
handler.SetUpCIDGroup(r) // CID,持续集成、部署
r.Run(":8083") // listen and serve on 0.0.0.0:8082
defer dao.Close()
defer worker.CloseRedis()
}
func init() {
// 创建cid的目录
os.MkdirAll(proto.CID_BASE_DIR, os.ModePerm)
os.MkdirAll(proto.CID_BASE_DIR+"script", os.ModePerm)
os.MkdirAll(proto.CID_BASE_DIR+"workspace", os.ModePerm)
}
func writeLogger(c *gin.Context) {
ip := c.ClientIP()

View File

@ -15,6 +15,9 @@ const (
REIDS_DB = 2
TOKEN_SECRET = "mfjurnc_32ndj9dfhj"
// 以下是持续集成、部署的配置
CID_BASE_DIR = "/home/lijun/cid/"
)
type User struct {