mirror of
https://gitee.com/dromara/mayfly-go
synced 2026-02-13 16:25:37 +08:00
refactor: 后端包结构重构、去除无用的文件
This commit is contained in:
289
server/internal/devops/api/db.go
Normal file
289
server/internal/devops/api/db.go
Normal file
@@ -0,0 +1,289 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"mayfly-go/internal/devops/api/form"
|
||||
"mayfly-go/internal/devops/api/vo"
|
||||
"mayfly-go/internal/devops/application"
|
||||
"mayfly-go/internal/devops/domain/entity"
|
||||
sysApplication "mayfly-go/internal/sys/application"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ctx"
|
||||
"mayfly-go/pkg/ginx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils"
|
||||
"mayfly-go/pkg/ws"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Db struct {
|
||||
DbApp application.Db
|
||||
MsgApp sysApplication.Msg
|
||||
ProjectApp application.Project
|
||||
}
|
||||
|
||||
// @router /api/dbs [get]
|
||||
func (d *Db) Dbs(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
m := &entity.Db{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
|
||||
ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
|
||||
}
|
||||
m.CreatorId = rc.LoginAccount.Id
|
||||
rc.ResData = d.DbApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]vo.SelectDataDbVO))
|
||||
}
|
||||
|
||||
func (d *Db) Save(rc *ctx.ReqCtx) {
|
||||
form := &form.DbForm{}
|
||||
ginx.BindJsonAndValid(rc.GinCtx, form)
|
||||
|
||||
rc.ReqParam = form
|
||||
|
||||
db := new(entity.Db)
|
||||
utils.Copy(db, form)
|
||||
db.SetBaseInfo(rc.LoginAccount)
|
||||
d.DbApp.Save(db)
|
||||
}
|
||||
|
||||
func (d *Db) DeleteDb(rc *ctx.ReqCtx) {
|
||||
d.DbApp.Delete(GetDbId(rc.GinCtx))
|
||||
}
|
||||
|
||||
func (d *Db) TableInfos(rc *ctx.ReqCtx) {
|
||||
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableInfos()
|
||||
}
|
||||
|
||||
func (d *Db) TableIndex(rc *ctx.ReqCtx) {
|
||||
tn := rc.GinCtx.Query("tableName")
|
||||
biz.NotEmpty(tn, "tableName不能为空")
|
||||
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableIndex(tn)
|
||||
}
|
||||
|
||||
func (d *Db) GetCreateTableDdl(rc *ctx.ReqCtx) {
|
||||
tn := rc.GinCtx.Query("tableName")
|
||||
biz.NotEmpty(tn, "tableName不能为空")
|
||||
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetCreateTableDdl(tn)
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/exec-sql [get]
|
||||
func (d *Db) ExecSql(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
|
||||
id, db := GetIdAndDb(g)
|
||||
dbInstance := d.DbApp.GetDbInstance(id, db)
|
||||
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "%s")
|
||||
|
||||
// 去除前后空格及换行符
|
||||
sql := strings.TrimFunc(g.Query("sql"), func(r rune) bool {
|
||||
s := string(r)
|
||||
return s == " " || s == "\n"
|
||||
})
|
||||
rc.ReqParam = fmt.Sprintf("db: %d:%s | sql: %s", id, db, sql)
|
||||
|
||||
biz.NotEmpty(sql, "sql不能为空")
|
||||
if strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select") || strings.HasPrefix(sql, "show") {
|
||||
colNames, res, err := dbInstance.SelectData(sql)
|
||||
biz.ErrIsNilAppendErr(err, "查询失败: %s")
|
||||
colAndRes := make(map[string]interface{})
|
||||
colAndRes["colNames"] = colNames
|
||||
colAndRes["res"] = res
|
||||
rc.ResData = colAndRes
|
||||
} else {
|
||||
rowsAffected, err := dbInstance.Exec(sql)
|
||||
biz.ErrIsNilAppendErr(err, "执行失败: %s")
|
||||
res := make([]map[string]string, 0)
|
||||
resData := make(map[string]string)
|
||||
resData["影响条数"] = fmt.Sprintf("%d", rowsAffected)
|
||||
res = append(res, resData)
|
||||
|
||||
colAndRes := make(map[string]interface{})
|
||||
colAndRes["colNames"] = []string{"影响条数"}
|
||||
colAndRes["res"] = res
|
||||
|
||||
rc.ResData = colAndRes
|
||||
}
|
||||
}
|
||||
|
||||
// 执行sql文件
|
||||
func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fileheader, err := g.FormFile("file")
|
||||
biz.ErrIsNilAppendErr(err, "读取sql文件失败: %s")
|
||||
|
||||
// 读取sql文件并根据;切割sql语句
|
||||
file, _ := fileheader.Open()
|
||||
filename := fileheader.Filename
|
||||
bytes, _ := ioutil.ReadAll(file)
|
||||
sqlContent := string(bytes)
|
||||
sqls := strings.Split(sqlContent, ";")
|
||||
dbId, db := GetIdAndDb(g)
|
||||
|
||||
go func() {
|
||||
db := d.DbApp.GetDbInstance(dbId, db)
|
||||
|
||||
dbEntity := d.DbApp.GetById(dbId)
|
||||
dbInfo := fmt.Sprintf("于%s的%s环境", dbEntity.Name, dbEntity.Env)
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, t.Error())))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, db.ProjectId), "%s")
|
||||
|
||||
for _, sql := range sqls {
|
||||
sql = strings.Trim(sql, " ")
|
||||
if sql == "" || sql == "\n" {
|
||||
continue
|
||||
}
|
||||
_, err := db.Exec(sql)
|
||||
if err != nil {
|
||||
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, err.Error())))
|
||||
return
|
||||
}
|
||||
}
|
||||
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.SuccessMsg("sql脚本执行成功", fmt.Sprintf("[%s]%s执行完成", filename, dbInfo)))
|
||||
}()
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/t-metadata [get]
|
||||
func (d *Db) TableMA(rc *ctx.ReqCtx) {
|
||||
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
|
||||
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
|
||||
rc.ResData = dbi.GetTableMetedatas()
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/c-metadata [get]
|
||||
func (d *Db) ColumnMA(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
tn := g.Query("tableName")
|
||||
biz.NotEmpty(tn, "tableName不能为空")
|
||||
|
||||
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
|
||||
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
|
||||
rc.ResData = dbi.GetColumnMetadatas(tn)
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/hint-tables [get]
|
||||
func (d *Db) HintTables(rc *ctx.ReqCtx) {
|
||||
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
|
||||
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
|
||||
// 获取所有表
|
||||
tables := dbi.GetTableMetedatas()
|
||||
|
||||
tableNames := make([]string, 0)
|
||||
for _, v := range tables {
|
||||
tableNames = append(tableNames, v["tableName"])
|
||||
}
|
||||
// key = 表名,value = 列名数组
|
||||
res := make(map[string][]string)
|
||||
|
||||
// 表为空,则直接返回
|
||||
if len(tableNames) == 0 {
|
||||
rc.ResData = res
|
||||
return
|
||||
}
|
||||
|
||||
// 获取所有表下的所有列信息
|
||||
columnMds := dbi.GetColumnMetadatas(tableNames...)
|
||||
for _, v := range columnMds {
|
||||
tName := v["tableName"]
|
||||
if res[tName] == nil {
|
||||
res[tName] = make([]string, 0)
|
||||
}
|
||||
|
||||
columnName := fmt.Sprintf("%s [%s]", v["columnName"], v["columnType"])
|
||||
comment := v["columnComment"]
|
||||
// 如果字段备注不为空,则加上备注信息
|
||||
if comment != "" {
|
||||
columnName = fmt.Sprintf("%s[%s]", columnName, comment)
|
||||
}
|
||||
|
||||
res[tName] = append(res[tName], columnName)
|
||||
}
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/sql [post]
|
||||
func (d *Db) SaveSql(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
account := rc.LoginAccount
|
||||
dbSqlForm := &form.DbSqlSaveForm{}
|
||||
ginx.BindJsonAndValid(g, dbSqlForm)
|
||||
rc.ReqParam = dbSqlForm
|
||||
|
||||
dbId := GetDbId(g)
|
||||
// 判断dbId是否存在
|
||||
err := model.GetById(new(entity.Db), dbId)
|
||||
biz.ErrIsNil(err, "该数据库信息不存在")
|
||||
|
||||
// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
|
||||
dbSql := &entity.DbSql{Type: dbSqlForm.Type, DbId: dbId, Name: dbSqlForm.Name, Db: dbSqlForm.Db}
|
||||
dbSql.CreatorId = account.Id
|
||||
e := model.GetBy(dbSql)
|
||||
|
||||
dbSql.SetBaseInfo(account)
|
||||
// 更新sql信息
|
||||
dbSql.Sql = dbSqlForm.Sql
|
||||
if e == nil {
|
||||
model.UpdateById(dbSql)
|
||||
} else {
|
||||
model.Insert(dbSql)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有保存的sql names
|
||||
func (d *Db) GetSqlNames(rc *ctx.ReqCtx) {
|
||||
id, db := GetIdAndDb(rc.GinCtx)
|
||||
// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
|
||||
dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
|
||||
dbSql.CreatorId = rc.LoginAccount.Id
|
||||
var sqls []entity.DbSql
|
||||
model.ListBy(dbSql, &sqls, "id", "name")
|
||||
|
||||
rc.ResData = sqls
|
||||
}
|
||||
|
||||
// 删除保存的sql
|
||||
func (d *Db) DeleteSql(rc *ctx.ReqCtx) {
|
||||
dbSql := &entity.DbSql{Type: 1, DbId: GetDbId(rc.GinCtx)}
|
||||
dbSql.CreatorId = rc.LoginAccount.Id
|
||||
dbSql.Name = rc.GinCtx.Query("name")
|
||||
|
||||
model.DeleteByCondition(dbSql)
|
||||
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/sql [get]
|
||||
func (d *Db) GetSql(rc *ctx.ReqCtx) {
|
||||
id, db := GetIdAndDb(rc.GinCtx)
|
||||
// 根据创建者id, 数据库id,以及sql模板名称查询保存的sql信息
|
||||
dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
|
||||
dbSql.CreatorId = rc.LoginAccount.Id
|
||||
dbSql.Name = rc.GinCtx.Query("name")
|
||||
|
||||
e := model.GetBy(dbSql)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
rc.ResData = dbSql
|
||||
}
|
||||
|
||||
func GetDbId(g *gin.Context) uint64 {
|
||||
dbId, _ := strconv.Atoi(g.Param("dbId"))
|
||||
biz.IsTrue(dbId > 0, "dbId错误")
|
||||
return uint64(dbId)
|
||||
}
|
||||
|
||||
func GetIdAndDb(g *gin.Context) (uint64, string) {
|
||||
db := g.Query("db")
|
||||
biz.NotEmpty(db, "db不能为空")
|
||||
return GetDbId(g), db
|
||||
}
|
||||
16
server/internal/devops/api/form/db.go
Normal file
16
server/internal/devops/api/form/db.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package form
|
||||
|
||||
type DbForm struct {
|
||||
Id uint64
|
||||
Name string `binding:"required" json:"name"`
|
||||
Type string `binding:"required" json:"type"` // 类型,mysql oracle等
|
||||
Host string `binding:"required" json:"host"`
|
||||
Port int `binding:"required" json:"port"`
|
||||
Username string `binding:"required" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Database string `binding:"required" json:"database"`
|
||||
ProjectId uint64 `binding:"required" json:"projectId"`
|
||||
Project string `json:"project"`
|
||||
Env string `json:"env"`
|
||||
EnvId uint64 `binding:"required" json:"envId"`
|
||||
}
|
||||
52
server/internal/devops/api/form/form.go
Normal file
52
server/internal/devops/api/form/form.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package form
|
||||
|
||||
type MachineForm struct {
|
||||
Id uint64 `json:"id"`
|
||||
ProjectId uint64 `json:"projectId"`
|
||||
ProjectName string `json:"projectName"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
// IP地址
|
||||
Ip string `json:"ip" binding:"required"`
|
||||
// 用户名
|
||||
Username string `json:"username" binding:"required"`
|
||||
Password string `json:"password"`
|
||||
// 端口号
|
||||
Port int `json:"port" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type MachineRunForm struct {
|
||||
MachineId int64 `binding:"required"`
|
||||
Cmd string `binding:"required"`
|
||||
}
|
||||
|
||||
type MachineFileForm struct {
|
||||
Id uint64
|
||||
Name string `binding:"required"`
|
||||
MachineId uint64 `binding:"required"`
|
||||
Type int `binding:"required"`
|
||||
Path string `binding:"required"`
|
||||
}
|
||||
|
||||
type MachineScriptForm struct {
|
||||
Id uint64
|
||||
Name string `binding:"required"`
|
||||
MachineId uint64 `binding:"required"`
|
||||
Type int `binding:"required"`
|
||||
Description string `binding:"required"`
|
||||
Params string
|
||||
Script string `binding:"required"`
|
||||
}
|
||||
|
||||
type DbSqlSaveForm struct {
|
||||
Name string
|
||||
Sql string `binding:"required"`
|
||||
Type int `binding:"required"`
|
||||
Db string `binding:"required"`
|
||||
}
|
||||
|
||||
type MachineFileUpdateForm struct {
|
||||
Content string `binding:"required"`
|
||||
Id uint64 `binding:"required"`
|
||||
Path string `binding:"required"`
|
||||
}
|
||||
40
server/internal/devops/api/form/mongo.go
Normal file
40
server/internal/devops/api/form/mongo.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package form
|
||||
|
||||
type Mongo struct {
|
||||
Id uint64
|
||||
Uri string `binding:"required" json:"uri"`
|
||||
Name string `binding:"required" json:"name"`
|
||||
ProjectId uint64 `binding:"required" json:"projectId"`
|
||||
Project string `json:"project"`
|
||||
Env string `json:"env"`
|
||||
EnvId uint64 `binding:"required" json:"envId"`
|
||||
}
|
||||
|
||||
type MongoCommand struct {
|
||||
Database string `binding:"required" json:"database"`
|
||||
Collection string `binding:"required" json:"collection"`
|
||||
Filter map[string]interface{} `json:"filter"`
|
||||
}
|
||||
|
||||
type MongoRunCommand struct {
|
||||
Database string `binding:"required" json:"database"`
|
||||
Command map[string]interface{} `json:"command"`
|
||||
}
|
||||
|
||||
type MongoFindCommand struct {
|
||||
MongoCommand
|
||||
Sort map[string]interface{} `json:"sort"`
|
||||
Skip int64
|
||||
Limit int64
|
||||
}
|
||||
|
||||
type MongoUpdateByIdCommand struct {
|
||||
MongoCommand
|
||||
DocId interface{} `binding:"required" json:"docId"`
|
||||
Update map[string]interface{} `json:"update"`
|
||||
}
|
||||
|
||||
type MongoInsertCommand struct {
|
||||
MongoCommand
|
||||
Doc map[string]interface{} `json:"doc"`
|
||||
}
|
||||
32
server/internal/devops/api/form/redis.go
Normal file
32
server/internal/devops/api/form/redis.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package form
|
||||
|
||||
type Redis struct {
|
||||
Id uint64
|
||||
Host string `binding:"required" json:"host"`
|
||||
Password string `json:"password"`
|
||||
Db int `json:"db"`
|
||||
ProjectId uint64 `binding:"required" json:"projectId"`
|
||||
Project string `json:"project"`
|
||||
Env string `json:"env"`
|
||||
EnvId uint64 `binding:"required" json:"envId"`
|
||||
}
|
||||
|
||||
type KeyInfo struct {
|
||||
Key string `binding:"required" json:"key"`
|
||||
Timed int64
|
||||
}
|
||||
|
||||
type StringValue struct {
|
||||
KeyInfo
|
||||
Value interface{} `binding:"required" json:"value"`
|
||||
}
|
||||
|
||||
type HashValue struct {
|
||||
KeyInfo
|
||||
Value []map[string]interface{} `binding:"required" json:"value"`
|
||||
}
|
||||
|
||||
type SetValue struct {
|
||||
KeyInfo
|
||||
Value []interface{} `binding:"required" json:"value"`
|
||||
}
|
||||
165
server/internal/devops/api/machine.go
Normal file
165
server/internal/devops/api/machine.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/devops/api/form"
|
||||
"mayfly-go/internal/devops/api/vo"
|
||||
"mayfly-go/internal/devops/application"
|
||||
"mayfly-go/internal/devops/domain/entity"
|
||||
"mayfly-go/internal/devops/infrastructure/machine"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ctx"
|
||||
"mayfly-go/pkg/ginx"
|
||||
"mayfly-go/pkg/utils"
|
||||
"mayfly-go/pkg/ws"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type Machine struct {
|
||||
MachineApp application.Machine
|
||||
ProjectApp application.Project
|
||||
}
|
||||
|
||||
func (m *Machine) Machines(rc *ctx.ReqCtx) {
|
||||
condition := new(entity.Machine)
|
||||
// 使用创建者id模拟账号成员id
|
||||
condition.CreatorId = rc.LoginAccount.Id
|
||||
condition.Ip = rc.GinCtx.Query("ip")
|
||||
condition.Name = rc.GinCtx.Query("name")
|
||||
condition.ProjectId = uint64(ginx.QueryInt(rc.GinCtx, "projectId", 0))
|
||||
|
||||
res := m.MachineApp.GetMachineList(condition, ginx.GetPageParam(rc.GinCtx), new([]*vo.MachineVO))
|
||||
if res.Total == 0 {
|
||||
rc.ResData = res
|
||||
return
|
||||
}
|
||||
|
||||
list := res.List.(*[]*vo.MachineVO)
|
||||
for _, mv := range *list {
|
||||
mv.HasCli = machine.HasCli(*mv.Id)
|
||||
}
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Machine) MachineStats(rc *ctx.ReqCtx) {
|
||||
stats := m.MachineApp.GetCli(GetMachineId(rc.GinCtx)).GetAllStats()
|
||||
rc.ResData = stats
|
||||
}
|
||||
|
||||
func (m *Machine) SaveMachine(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
machineForm := new(form.MachineForm)
|
||||
ginx.BindJsonAndValid(g, machineForm)
|
||||
|
||||
entity := new(entity.Machine)
|
||||
utils.Copy(entity, machineForm)
|
||||
|
||||
entity.SetBaseInfo(rc.LoginAccount)
|
||||
m.MachineApp.Save(entity)
|
||||
}
|
||||
|
||||
func (m *Machine) ChangeStatus(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
id := uint64(ginx.PathParamInt(g, "machineId"))
|
||||
status := int8(ginx.PathParamInt(g, "status"))
|
||||
rc.ReqParam = fmt.Sprintf("id: %d -- status: %d", id, status)
|
||||
m.MachineApp.ChangeStatus(id, status)
|
||||
}
|
||||
|
||||
func (m *Machine) DeleteMachine(rc *ctx.ReqCtx) {
|
||||
id := uint64(ginx.PathParamInt(rc.GinCtx, "machineId"))
|
||||
rc.ReqParam = id
|
||||
m.MachineApp.Delete(id)
|
||||
}
|
||||
|
||||
// 关闭机器客户端
|
||||
func (m *Machine) CloseCli(rc *ctx.ReqCtx) {
|
||||
machine.DeleteCli(GetMachineId(rc.GinCtx))
|
||||
}
|
||||
|
||||
// 获取进程列表信息
|
||||
func (m *Machine) GetProcess(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
cmd := "ps -aux "
|
||||
sortType := g.Query("sortType")
|
||||
if sortType == "2" {
|
||||
cmd += "--sort -pmem "
|
||||
} else {
|
||||
cmd += "--sort -pcpu "
|
||||
}
|
||||
|
||||
pname := g.Query("name")
|
||||
if pname != "" {
|
||||
cmd += fmt.Sprintf("| grep %s ", pname)
|
||||
}
|
||||
|
||||
count := g.Query("count")
|
||||
if count == "" {
|
||||
count = "10"
|
||||
}
|
||||
|
||||
cmd += "| head -n " + count
|
||||
|
||||
cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
|
||||
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
|
||||
|
||||
res, err := cli.Run(cmd)
|
||||
biz.ErrIsNilAppendErr(err, "获取进程信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
// 终止进程
|
||||
func (m *Machine) KillProcess(rc *ctx.ReqCtx) {
|
||||
pid := rc.GinCtx.Query("pid")
|
||||
biz.NotEmpty(pid, "进程id不能为空")
|
||||
|
||||
cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
|
||||
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
|
||||
|
||||
_, err := cli.Run("kill -9 " + pid)
|
||||
biz.ErrIsNilAppendErr(err, "终止进程失败: %s")
|
||||
}
|
||||
|
||||
func (m *Machine) WsSSH(g *gin.Context) {
|
||||
wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte(err.(error).Error()))
|
||||
wsConn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
panic(biz.NewBizErr("升级websocket失败"))
|
||||
}
|
||||
// 权限校验
|
||||
rc := ctx.NewReqCtxWithGin(g).WithRequiredPermission(ctx.NewPermission("machine:terminal"))
|
||||
if err = ctx.PermissionHandler(rc); err != nil {
|
||||
panic(biz.NewBizErr("没有权限"))
|
||||
}
|
||||
|
||||
cols := ginx.QueryInt(g, "cols", 80)
|
||||
rows := ginx.QueryInt(g, "rows", 40)
|
||||
|
||||
cli := m.MachineApp.GetCli(GetMachineId(g))
|
||||
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
|
||||
|
||||
sws, err := machine.NewLogicSshWsSession(cols, rows, cli, wsConn)
|
||||
biz.ErrIsNilAppendErr(err, "连接失败:%s")
|
||||
defer sws.Close()
|
||||
|
||||
quitChan := make(chan bool, 3)
|
||||
sws.Start(quitChan)
|
||||
go sws.Wait(quitChan)
|
||||
|
||||
<-quitChan
|
||||
}
|
||||
|
||||
func GetMachineId(g *gin.Context) uint64 {
|
||||
machineId, _ := strconv.Atoi(g.Param("machineId"))
|
||||
biz.IsTrue(machineId != 0, "machineId错误")
|
||||
return uint64(machineId)
|
||||
}
|
||||
177
server/internal/devops/api/machine_file.go
Normal file
177
server/internal/devops/api/machine_file.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"mayfly-go/internal/devops/api/form"
|
||||
"mayfly-go/internal/devops/api/vo"
|
||||
"mayfly-go/internal/devops/application"
|
||||
"mayfly-go/internal/devops/domain/entity"
|
||||
sysApplication "mayfly-go/internal/sys/application"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ctx"
|
||||
"mayfly-go/pkg/ginx"
|
||||
"mayfly-go/pkg/utils"
|
||||
"mayfly-go/pkg/ws"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type MachineFile struct {
|
||||
MachineFileApp application.MachineFile
|
||||
MachineApp application.Machine
|
||||
MsgApp sysApplication.Msg
|
||||
}
|
||||
|
||||
const (
|
||||
file = "-"
|
||||
dir = "d"
|
||||
link = "l"
|
||||
max_read_size = 1 * 1024 * 1024
|
||||
)
|
||||
|
||||
func (m *MachineFile) MachineFiles(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
condition := &entity.MachineFile{MachineId: GetMachineId(g)}
|
||||
rc.ResData = m.MachineFileApp.GetPageList(condition, ginx.GetPageParam(g), new([]vo.MachineFileVO))
|
||||
}
|
||||
|
||||
func (m *MachineFile) SaveMachineFiles(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fileForm := new(form.MachineFileForm)
|
||||
ginx.BindJsonAndValid(g, fileForm)
|
||||
|
||||
entity := new(entity.MachineFile)
|
||||
utils.Copy(entity, fileForm)
|
||||
|
||||
entity.SetBaseInfo(rc.LoginAccount)
|
||||
|
||||
m.MachineFileApp.Save(entity)
|
||||
}
|
||||
|
||||
func (m *MachineFile) DeleteFile(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fid := GetMachineFileId(g)
|
||||
m.MachineFileApp.Delete(fid)
|
||||
}
|
||||
|
||||
/*** sftp相关操作 */
|
||||
|
||||
func (m *MachineFile) ReadFileContent(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fid := GetMachineFileId(g)
|
||||
readPath := g.Query("path")
|
||||
readType := g.Query("type")
|
||||
|
||||
sftpFile := m.MachineFileApp.ReadFile(fid, readPath)
|
||||
defer sftpFile.Close()
|
||||
|
||||
fileInfo, _ := sftpFile.Stat()
|
||||
// 如果是读取文件内容,则校验文件大小
|
||||
if readType != "1" {
|
||||
biz.IsTrue(fileInfo.Size() < max_read_size, "文件超过1m,请使用下载查看")
|
||||
}
|
||||
|
||||
rc.ReqParam = fmt.Sprintf("path: %s", readPath)
|
||||
// 如果读取类型为下载,则下载文件,否则获取文件内容
|
||||
if readType == "1" {
|
||||
// 截取文件名,如/usr/local/test.java -》 test.java
|
||||
path := strings.Split(readPath, "/")
|
||||
rc.Download(sftpFile, path[len(path)-1])
|
||||
} else {
|
||||
datas, err := ioutil.ReadAll(sftpFile)
|
||||
biz.ErrIsNilAppendErr(err, "读取文件内容失败: %s")
|
||||
rc.ResData = string(datas)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MachineFile) GetDirEntry(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fid := GetMachineFileId(g)
|
||||
readPath := g.Query("path")
|
||||
|
||||
if !strings.HasSuffix(readPath, "/") {
|
||||
readPath = readPath + "/"
|
||||
}
|
||||
fis := m.MachineFileApp.ReadDir(fid, readPath)
|
||||
fisVO := make([]vo.MachineFileInfo, 0)
|
||||
for _, fi := range fis {
|
||||
fisVO = append(fisVO, vo.MachineFileInfo{
|
||||
Name: fi.Name(),
|
||||
Size: fi.Size(),
|
||||
Path: readPath + fi.Name(),
|
||||
Type: getFileType(fi.Mode()),
|
||||
})
|
||||
}
|
||||
rc.ResData = fisVO
|
||||
rc.ReqParam = fmt.Sprintf("path: %s", readPath)
|
||||
}
|
||||
|
||||
func (m *MachineFile) WriteFileContent(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fid := GetMachineFileId(g)
|
||||
|
||||
form := new(form.MachineFileUpdateForm)
|
||||
ginx.BindJsonAndValid(g, form)
|
||||
path := form.Path
|
||||
|
||||
m.MachineFileApp.WriteFileContent(fid, path, []byte(form.Content))
|
||||
|
||||
rc.ReqParam = fmt.Sprintf("path: %s", path)
|
||||
}
|
||||
|
||||
func (m *MachineFile) UploadFile(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fid := GetMachineFileId(g)
|
||||
path := g.PostForm("path")
|
||||
|
||||
fileheader, err := g.FormFile("file")
|
||||
biz.ErrIsNilAppendErr(err, "读取文件失败: %s")
|
||||
|
||||
file, _ := fileheader.Open()
|
||||
rc.ReqParam = fmt.Sprintf("path: %s", path)
|
||||
|
||||
la := rc.LoginAccount
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
m.MsgApp.CreateAndSend(la, ws.ErrMsg("文件上传失败", fmt.Sprintf("执行文件上传失败:\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())))
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer file.Close()
|
||||
m.MachineFileApp.UploadFile(fid, path, fileheader.Filename, file)
|
||||
// 保存消息并发送文件上传成功通知
|
||||
machine := m.MachineApp.GetById(m.MachineFileApp.GetById(fid).MachineId)
|
||||
m.MsgApp.CreateAndSend(la, ws.SuccessMsg("文件上传成功", fmt.Sprintf("[%s]文件已成功上传至 %s[%s:%s]", fileheader.Filename, machine.Name, machine.Ip, path)))
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *MachineFile) RemoveFile(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
fid := GetMachineFileId(g)
|
||||
// mid := GetMachineId(g)
|
||||
path := g.Query("path")
|
||||
|
||||
m.MachineFileApp.RemoveFile(fid, path)
|
||||
|
||||
rc.ReqParam = fmt.Sprintf("path: %s", path)
|
||||
}
|
||||
|
||||
func getFileType(fm fs.FileMode) string {
|
||||
if fm.IsDir() {
|
||||
return dir
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
func GetMachineFileId(g *gin.Context) uint64 {
|
||||
fileId, _ := strconv.Atoi(g.Param("fileId"))
|
||||
biz.IsTrue(fileId != 0, "fileId错误")
|
||||
return uint64(fileId)
|
||||
}
|
||||
82
server/internal/devops/api/machine_script.go
Normal file
82
server/internal/devops/api/machine_script.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/devops/api/form"
|
||||
"mayfly-go/internal/devops/api/vo"
|
||||
"mayfly-go/internal/devops/application"
|
||||
"mayfly-go/internal/devops/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ctx"
|
||||
"mayfly-go/pkg/ginx"
|
||||
"mayfly-go/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type MachineScript struct {
|
||||
MachineScriptApp application.MachineScript
|
||||
MachineApp application.Machine
|
||||
ProjectApp application.Project
|
||||
}
|
||||
|
||||
func (m *MachineScript) MachineScripts(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
condition := &entity.MachineScript{MachineId: GetMachineId(g)}
|
||||
rc.ResData = m.MachineScriptApp.GetPageList(condition, ginx.GetPageParam(g), new([]vo.MachineScriptVO))
|
||||
}
|
||||
|
||||
func (m *MachineScript) SaveMachineScript(rc *ctx.ReqCtx) {
|
||||
form := new(form.MachineScriptForm)
|
||||
ginx.BindJsonAndValid(rc.GinCtx, form)
|
||||
rc.ReqParam = form
|
||||
|
||||
// 转换为entity,并设置基本信息
|
||||
machineScript := new(entity.MachineScript)
|
||||
utils.Copy(machineScript, form)
|
||||
machineScript.SetBaseInfo(rc.LoginAccount)
|
||||
|
||||
m.MachineScriptApp.Save(machineScript)
|
||||
}
|
||||
|
||||
func (m *MachineScript) DeleteMachineScript(rc *ctx.ReqCtx) {
|
||||
msa := m.MachineScriptApp
|
||||
sid := GetMachineScriptId(rc.GinCtx)
|
||||
ms := msa.GetById(sid)
|
||||
biz.NotNil(ms, "该脚本不存在")
|
||||
rc.ReqParam = fmt.Sprintf("[scriptId: %d, name: %s, desc: %s, script: %s]", sid, ms.Name, ms.Description, ms.Script)
|
||||
msa.Delete(sid)
|
||||
}
|
||||
|
||||
func (m *MachineScript) RunMachineScript(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
|
||||
scriptId := GetMachineScriptId(g)
|
||||
machineId := GetMachineId(g)
|
||||
ms := m.MachineScriptApp.GetById(scriptId, "MachineId", "Name", "Script")
|
||||
biz.NotNil(ms, "该脚本不存在")
|
||||
biz.IsTrue(ms.MachineId == application.Common_Script_Machine_Id || ms.MachineId == machineId, "该脚本不属于该机器")
|
||||
|
||||
script := ms.Script
|
||||
// 如果有脚本参数,则用脚本参数替换脚本中的模板占位符参数
|
||||
if params := g.Query("params"); params != "" {
|
||||
script = utils.TemplateParse(ms.Script, utils.Json2Map(params))
|
||||
}
|
||||
cli := m.MachineApp.GetCli(machineId)
|
||||
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
|
||||
|
||||
res, err := cli.Run(script)
|
||||
// 记录请求参数
|
||||
rc.ReqParam = fmt.Sprintf("[machineId: %d, scriptId: %d, name: %s]", machineId, scriptId, ms.Name)
|
||||
if err != nil {
|
||||
panic(biz.NewBizErr(fmt.Sprintf("执行命令失败:%s", err.Error())))
|
||||
}
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func GetMachineScriptId(g *gin.Context) uint64 {
|
||||
scriptId, _ := strconv.Atoi(g.Param("scriptId"))
|
||||
biz.IsTrue(scriptId > 0, "scriptId错误")
|
||||
return uint64(scriptId)
|
||||
}
|
||||
168
server/internal/devops/api/mongo.go
Normal file
168
server/internal/devops/api/mongo.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/devops/api/form"
|
||||
"mayfly-go/internal/devops/application"
|
||||
"mayfly-go/internal/devops/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ctx"
|
||||
"mayfly-go/pkg/ginx"
|
||||
"mayfly-go/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type Mongo struct {
|
||||
MongoApp application.Mongo
|
||||
}
|
||||
|
||||
func (m *Mongo) Mongos(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
mc := &entity.Mongo{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
|
||||
ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
|
||||
}
|
||||
mc.CreatorId = rc.LoginAccount.Id
|
||||
rc.ResData = m.MongoApp.GetPageList(mc, ginx.GetPageParam(rc.GinCtx), new([]entity.Mongo))
|
||||
}
|
||||
|
||||
func (m *Mongo) Save(rc *ctx.ReqCtx) {
|
||||
form := &form.Mongo{}
|
||||
ginx.BindJsonAndValid(rc.GinCtx, form)
|
||||
|
||||
rc.ReqParam = form
|
||||
|
||||
mongo := new(entity.Mongo)
|
||||
utils.Copy(mongo, form)
|
||||
mongo.SetBaseInfo(rc.LoginAccount)
|
||||
m.MongoApp.Save(mongo)
|
||||
}
|
||||
|
||||
func (m *Mongo) DeleteMongo(rc *ctx.ReqCtx) {
|
||||
m.MongoApp.Delete(m.GetMongoId(rc.GinCtx))
|
||||
}
|
||||
|
||||
func (m *Mongo) Databases(rc *ctx.ReqCtx) {
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
||||
res, err := cli.ListDatabases(context.TODO(), bson.D{})
|
||||
biz.ErrIsNilAppendErr(err, "获取mongo所有库信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) Collections(rc *ctx.ReqCtx) {
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
||||
db := rc.GinCtx.Query("database")
|
||||
biz.NotEmpty(db, "database不能为空")
|
||||
ctx := context.TODO()
|
||||
res, err := cli.Database(db).ListCollectionNames(ctx, bson.D{})
|
||||
biz.ErrIsNilAppendErr(err, "获取库集合信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) RunCommand(rc *ctx.ReqCtx) {
|
||||
commandForm := new(form.MongoRunCommand)
|
||||
ginx.BindJsonAndValid(rc.GinCtx, commandForm)
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
||||
|
||||
ctx := context.TODO()
|
||||
var bm bson.M
|
||||
err := cli.Database(commandForm.Database).RunCommand(
|
||||
ctx,
|
||||
commandForm.Command,
|
||||
).Decode(&bm)
|
||||
|
||||
biz.ErrIsNilAppendErr(err, "执行命令失败: %s")
|
||||
rc.ResData = bm
|
||||
}
|
||||
|
||||
func (m *Mongo) FindCommand(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
commandForm := new(form.MongoFindCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
limit := commandForm.Limit
|
||||
if limit != 0 {
|
||||
biz.IsTrue(limit <= 100, "limit不能超过100")
|
||||
}
|
||||
opts := options.Find().SetSort(commandForm.Sort).
|
||||
SetSkip(commandForm.Skip).
|
||||
SetLimit(limit)
|
||||
ctx := context.TODO()
|
||||
cur, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).Find(ctx, commandForm.Filter, opts)
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
|
||||
var res []bson.M
|
||||
cur.All(ctx, &res)
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) UpdateByIdCommand(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
commandForm := new(form.MongoUpdateByIdCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
// 解析docId文档id,如果为string类型则使用ObjectId解析,解析失败则为普通字符串
|
||||
docId := commandForm.DocId
|
||||
docIdVal, ok := docId.(string)
|
||||
if ok {
|
||||
objId, err := primitive.ObjectIDFromHex(docIdVal)
|
||||
if err == nil {
|
||||
docId = objId
|
||||
}
|
||||
}
|
||||
|
||||
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).UpdateByID(context.TODO(), docId, commandForm.Update)
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
|
||||
rc.ReqParam = commandForm
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) DeleteByIdCommand(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
commandForm := new(form.MongoUpdateByIdCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
// 解析docId文档id,如果为string类型则使用ObjectId解析,解析失败则为普通字符串
|
||||
docId := commandForm.DocId
|
||||
docIdVal, ok := docId.(string)
|
||||
if ok {
|
||||
objId, err := primitive.ObjectIDFromHex(docIdVal)
|
||||
if err == nil {
|
||||
docId = objId
|
||||
}
|
||||
}
|
||||
|
||||
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).DeleteOne(context.TODO(), bson.D{{"_id", docId}})
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
|
||||
rc.ReqParam = commandForm
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) InsertOneCommand(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
commandForm := new(form.MongoInsertCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).InsertOne(context.TODO(), commandForm.Doc)
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
|
||||
rc.ReqParam = commandForm
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
// 获取请求路径上的mongo id
|
||||
func (m *Mongo) GetMongoId(g *gin.Context) uint64 {
|
||||
dbId, _ := strconv.Atoi(g.Param("id"))
|
||||
biz.IsTrue(dbId > 0, "mongoId错误")
|
||||
return uint64(dbId)
|
||||
}
|
||||
104
server/internal/devops/api/project.go
Normal file
104
server/internal/devops/api/project.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/devops/api/vo"
|
||||
"mayfly-go/internal/devops/application"
|
||||
"mayfly-go/internal/devops/domain/entity"
|
||||
sys_applicaiton "mayfly-go/internal/sys/application"
|
||||
sys_entity "mayfly-go/internal/sys/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ctx"
|
||||
"mayfly-go/pkg/ginx"
|
||||
)
|
||||
|
||||
type Project struct {
|
||||
ProjectApp application.Project
|
||||
AccountApp sys_applicaiton.Account
|
||||
}
|
||||
|
||||
// 获取当前登录用户可以访问的项目列表
|
||||
func (p *Project) GetProjectsByLoginAccount(rc *ctx.ReqCtx) {
|
||||
// 获取登录用户拥有的项目ids
|
||||
projectMembers := &[]entity.ProjectMember{}
|
||||
p.ProjectApp.ListMember(&entity.ProjectMember{AccountId: rc.LoginAccount.Id}, projectMembers)
|
||||
var pids []uint64
|
||||
for _, pm := range *projectMembers {
|
||||
pids = append(pids, pm.ProjectId)
|
||||
}
|
||||
|
||||
// 获取项目信息
|
||||
projects := &vo.AccountProjects{}
|
||||
p.ProjectApp.ListProjectByIds(pids, projects)
|
||||
rc.ResData = projects
|
||||
}
|
||||
|
||||
func (p *Project) GetProjects(rc *ctx.ReqCtx) {
|
||||
condition := &entity.Project{}
|
||||
ginx.BindQuery(rc.GinCtx, condition)
|
||||
// condition.Name = rc.GinCtx.Query("name")
|
||||
rc.ResData = p.ProjectApp.GetPageList(condition, ginx.GetPageParam(rc.GinCtx), new([]entity.Project))
|
||||
}
|
||||
|
||||
func (p *Project) SaveProject(rc *ctx.ReqCtx) {
|
||||
project := &entity.Project{}
|
||||
ginx.BindJsonAndValid(rc.GinCtx, project)
|
||||
rc.ReqParam = project
|
||||
|
||||
project.SetBaseInfo(rc.LoginAccount)
|
||||
p.ProjectApp.SaveProject(project)
|
||||
}
|
||||
|
||||
func (p *Project) DelProject(rc *ctx.ReqCtx) {
|
||||
p.ProjectApp.DelProject(uint64(ginx.QueryInt(rc.GinCtx, "id", 0)))
|
||||
}
|
||||
|
||||
// 获取项目下的环境信息
|
||||
func (p *Project) GetProjectEnvs(rc *ctx.ReqCtx) {
|
||||
projectEnvs := &[]entity.ProjectEnv{}
|
||||
p.ProjectApp.ListEnvByProjectId(uint64(ginx.PathParamInt(rc.GinCtx, "projectId")), projectEnvs)
|
||||
rc.ResData = projectEnvs
|
||||
}
|
||||
|
||||
//保存项目下的环境信息
|
||||
func (p *Project) SaveProjectEnvs(rc *ctx.ReqCtx) {
|
||||
projectEnv := &entity.ProjectEnv{}
|
||||
ginx.BindJsonAndValid(rc.GinCtx, projectEnv)
|
||||
rc.ReqParam = projectEnv
|
||||
|
||||
projectEnv.SetBaseInfo(rc.LoginAccount)
|
||||
p.ProjectApp.SaveProjectEnv(projectEnv)
|
||||
}
|
||||
|
||||
// 获取项目下的成员信息
|
||||
func (p *Project) GetProjectMembers(rc *ctx.ReqCtx) {
|
||||
projectMems := &[]entity.ProjectMember{}
|
||||
rc.ResData = p.ProjectApp.GetMemberPage(&entity.ProjectMember{ProjectId: uint64(ginx.PathParamInt(rc.GinCtx, "projectId"))},
|
||||
ginx.GetPageParam(rc.GinCtx), projectMems)
|
||||
}
|
||||
|
||||
//保存项目的成员信息
|
||||
func (p *Project) SaveProjectMember(rc *ctx.ReqCtx) {
|
||||
projectMem := &entity.ProjectMember{}
|
||||
ginx.BindJsonAndValid(rc.GinCtx, projectMem)
|
||||
rc.ReqParam = projectMem
|
||||
|
||||
// 校验账号,并赋值username
|
||||
account := &sys_entity.Account{}
|
||||
account.Id = projectMem.AccountId
|
||||
biz.ErrIsNil(p.AccountApp.GetAccount(account, "Id", "Username"), "账号不存在")
|
||||
projectMem.Username = account.Username
|
||||
|
||||
projectMem.SetBaseInfo(rc.LoginAccount)
|
||||
p.ProjectApp.SaveProjectMember(projectMem)
|
||||
}
|
||||
|
||||
//删除项目成员
|
||||
func (p *Project) DelProjectMember(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
pid := ginx.PathParamInt(g, "projectId")
|
||||
aid := ginx.PathParamInt(g, "accountId")
|
||||
rc.ReqParam = fmt.Sprintf("projectId: %d, accountId: %d", pid, aid)
|
||||
|
||||
p.ProjectApp.DeleteMember(uint64(pid), uint64(aid))
|
||||
}
|
||||
216
server/internal/devops/api/redis.go
Normal file
216
server/internal/devops/api/redis.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/devops/api/form"
|
||||
"mayfly-go/internal/devops/api/vo"
|
||||
"mayfly-go/internal/devops/application"
|
||||
"mayfly-go/internal/devops/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ctx"
|
||||
"mayfly-go/pkg/ginx"
|
||||
"mayfly-go/pkg/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Redis struct {
|
||||
RedisApp application.Redis
|
||||
ProjectApp application.Project
|
||||
}
|
||||
|
||||
func (r *Redis) RedisList(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
m := &entity.Redis{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
|
||||
ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
|
||||
}
|
||||
m.CreatorId = rc.LoginAccount.Id
|
||||
rc.ResData = r.RedisApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]vo.Redis))
|
||||
}
|
||||
|
||||
func (r *Redis) Save(rc *ctx.ReqCtx) {
|
||||
form := &form.Redis{}
|
||||
ginx.BindJsonAndValid(rc.GinCtx, form)
|
||||
|
||||
rc.ReqParam = form
|
||||
|
||||
redis := new(entity.Redis)
|
||||
utils.Copy(redis, form)
|
||||
redis.SetBaseInfo(rc.LoginAccount)
|
||||
r.RedisApp.Save(redis)
|
||||
}
|
||||
|
||||
func (r *Redis) DeleteRedis(rc *ctx.ReqCtx) {
|
||||
r.RedisApp.Delete(uint64(ginx.PathParamInt(rc.GinCtx, "id")))
|
||||
}
|
||||
|
||||
func (r *Redis) RedisInfo(rc *ctx.ReqCtx) {
|
||||
res, _ := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(rc.GinCtx, "id"))).Cli.Info().Result()
|
||||
|
||||
datas := strings.Split(res, "\r\n")
|
||||
i := 0
|
||||
length := len(datas)
|
||||
|
||||
parseMap := make(map[string]map[string]string)
|
||||
for {
|
||||
if i >= length {
|
||||
break
|
||||
}
|
||||
if strings.Contains(datas[i], "#") {
|
||||
key := utils.SubString(datas[i], strings.Index(datas[i], "#")+1, utils.StrLen(datas[i]))
|
||||
i++
|
||||
key = strings.Trim(key, " ")
|
||||
|
||||
sectionMap := make(map[string]string)
|
||||
for {
|
||||
if i >= length || !strings.Contains(datas[i], ":") {
|
||||
break
|
||||
}
|
||||
pair := strings.Split(datas[i], ":")
|
||||
i++
|
||||
if len(pair) != 2 {
|
||||
continue
|
||||
}
|
||||
sectionMap[pair[0]] = pair[1]
|
||||
}
|
||||
parseMap[key] = sectionMap
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
rc.ResData = parseMap
|
||||
}
|
||||
|
||||
// scan获取redis的key列表信息
|
||||
func (r *Redis) Scan(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
|
||||
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
|
||||
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
|
||||
|
||||
keys, cursor := ri.Scan(uint64(ginx.PathParamInt(g, "cursor")), g.Query("match"), int64(ginx.PathParamInt(g, "count")))
|
||||
|
||||
var keyInfoSplit []string
|
||||
if len(keys) > 0 {
|
||||
keyInfoLua := `
|
||||
local result = {}
|
||||
-- KEYS[1]为第1个参数,lua数组下标从1开始
|
||||
local ttl = redis.call('ttl', KEYS[1]);
|
||||
local keyType = redis.call('type', KEYS[1]);
|
||||
for i = 1, #KEYS do
|
||||
local ttl = redis.call('ttl', KEYS[i]);
|
||||
local keyType = redis.call('type', KEYS[i]);
|
||||
table.insert(result, string.format("%d,%s", ttl, keyType['ok']));
|
||||
end;
|
||||
return table.concat(result, ".");`
|
||||
// 通过lua获取 ttl,type.ttl2,type2格式,以便下面切割获取ttl和type。避免多次调用ttl和type函数
|
||||
keyInfos, _ := ri.Cli.Eval(keyInfoLua, keys).Result()
|
||||
keyInfoSplit = strings.Split(keyInfos.(string), ".")
|
||||
}
|
||||
|
||||
kis := make([]*vo.KeyInfo, 0)
|
||||
for i, k := range keys {
|
||||
ttlType := strings.Split(keyInfoSplit[i], ",")
|
||||
ttl, _ := strconv.Atoi(ttlType[0])
|
||||
ki := &vo.KeyInfo{Key: k, Type: ttlType[1], Ttl: int64(ttl)}
|
||||
kis = append(kis, ki)
|
||||
}
|
||||
|
||||
size, _ := ri.Cli.DBSize().Result()
|
||||
rc.ResData = &vo.Keys{Cursor: cursor, Keys: kis, DbSize: size}
|
||||
}
|
||||
|
||||
func (r *Redis) DeleteKey(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
key := g.Query("key")
|
||||
biz.NotEmpty(key, "key不能为空")
|
||||
|
||||
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
|
||||
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
|
||||
|
||||
rc.ReqParam = key
|
||||
ri.Cli.Del(key)
|
||||
}
|
||||
|
||||
func (r *Redis) checkKey(rc *ctx.ReqCtx) (*application.RedisInstance, string) {
|
||||
g := rc.GinCtx
|
||||
key := g.Query("key")
|
||||
biz.NotEmpty(key, "key不能为空")
|
||||
|
||||
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
|
||||
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
|
||||
|
||||
return ri, key
|
||||
}
|
||||
|
||||
func (r *Redis) GetStringValue(rc *ctx.ReqCtx) {
|
||||
ri, key := r.checkKey(rc)
|
||||
str, err := ri.Cli.Get(key).Result()
|
||||
biz.ErrIsNilAppendErr(err, "获取字符串值失败: %s")
|
||||
rc.ResData = str
|
||||
}
|
||||
|
||||
func (r *Redis) GetHashValue(rc *ctx.ReqCtx) {
|
||||
ri, key := r.checkKey(rc)
|
||||
res, err := ri.Cli.HGetAll(key).Result()
|
||||
biz.ErrIsNilAppendErr(err, "获取hash值失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (r *Redis) SetStringValue(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
keyValue := new(form.StringValue)
|
||||
ginx.BindJsonAndValid(g, keyValue)
|
||||
|
||||
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
|
||||
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
|
||||
|
||||
str, err := ri.Cli.Set(keyValue.Key, keyValue.Value, time.Second*time.Duration(keyValue.Timed)).Result()
|
||||
biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s")
|
||||
rc.ResData = str
|
||||
}
|
||||
|
||||
func (r *Redis) SetHashValue(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
hashValue := new(form.HashValue)
|
||||
ginx.BindJsonAndValid(g, hashValue)
|
||||
|
||||
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
|
||||
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
|
||||
|
||||
key := hashValue.Key
|
||||
// 简单处理->先删除,后新增
|
||||
ri.Cli.Del(key)
|
||||
for _, v := range hashValue.Value {
|
||||
res := ri.Cli.HSet(key, v["key"].(string), v["value"])
|
||||
biz.ErrIsNilAppendErr(res.Err(), "保存hash值失败: %s")
|
||||
}
|
||||
if hashValue.Timed != -1 {
|
||||
ri.Cli.Expire(key, time.Second*time.Duration(hashValue.Timed))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Redis) GetSetValue(rc *ctx.ReqCtx) {
|
||||
ri, key := r.checkKey(rc)
|
||||
res, err := ri.Cli.SMembers(key).Result()
|
||||
biz.ErrIsNilAppendErr(err, "获取set值失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (r *Redis) SetSetValue(rc *ctx.ReqCtx) {
|
||||
g := rc.GinCtx
|
||||
keyvalue := new(form.SetValue)
|
||||
ginx.BindJsonAndValid(g, keyvalue)
|
||||
|
||||
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
|
||||
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
|
||||
|
||||
key := keyvalue.Key
|
||||
// 简单处理->先删除,后新增
|
||||
ri.Cli.Del(key)
|
||||
ri.Cli.SAdd(key, keyvalue.Value...)
|
||||
|
||||
if keyvalue.Timed != -1 {
|
||||
ri.Cli.Expire(key, time.Second*time.Duration(keyvalue.Timed))
|
||||
}
|
||||
}
|
||||
21
server/internal/devops/api/vo/db.go
Normal file
21
server/internal/devops/api/vo/db.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package vo
|
||||
|
||||
import "time"
|
||||
|
||||
type SelectDataDbVO struct {
|
||||
//models.BaseModel
|
||||
Id *int64 `json:"id"`
|
||||
Name *string `json:"name"`
|
||||
Host *string `json:"host"`
|
||||
Port *int `json:"port"`
|
||||
Type *string `json:"type"`
|
||||
Database *string `json:"database"`
|
||||
Username *string `json:"username"`
|
||||
ProjectId *int64 `json:"projectId"`
|
||||
Project *string `json:"project"`
|
||||
Env *string `json:"env"`
|
||||
EnvId *int64 `json:"envId"`
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
Creator *string `json:"creator"`
|
||||
CreatorId *int64 `json:"creatorId"`
|
||||
}
|
||||
10
server/internal/devops/api/vo/project.go
Normal file
10
server/internal/devops/api/vo/project.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package vo
|
||||
|
||||
// 用户选择项目
|
||||
type AccountProject struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type AccountProjects []AccountProject
|
||||
29
server/internal/devops/api/vo/redis.go
Normal file
29
server/internal/devops/api/vo/redis.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package vo
|
||||
|
||||
import "time"
|
||||
|
||||
type Redis struct {
|
||||
Id *int64 `json:"id"`
|
||||
// Name *string `json:"name"`
|
||||
Host *string `json:"host"`
|
||||
Db int `json:"db"`
|
||||
ProjectId *int64 `json:"projectId"`
|
||||
Project *string `json:"project"`
|
||||
Env *string `json:"env"`
|
||||
EnvId *int64 `json:"envId"`
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
Creator *string `json:"creator"`
|
||||
CreatorId *int64 `json:"creatorId"`
|
||||
}
|
||||
|
||||
type Keys struct {
|
||||
Cursor uint64 `json:"cursor"`
|
||||
Keys []*KeyInfo `json:"keys"`
|
||||
DbSize int64 `json:"dbSize"`
|
||||
}
|
||||
|
||||
type KeyInfo struct {
|
||||
Key string `json:"key"`
|
||||
Ttl int64 `json:"ttl"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
64
server/internal/devops/api/vo/vo.go
Normal file
64
server/internal/devops/api/vo/vo.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package vo
|
||||
|
||||
import "time"
|
||||
|
||||
type AccountVO struct {
|
||||
//models.BaseModel
|
||||
Id *int64 `json:"id"`
|
||||
Username *string `json:"username"`
|
||||
CreateTime *string `json:"createTime"`
|
||||
Creator *string `json:"creator"`
|
||||
CreatorId *int64 `json:"creatorId"`
|
||||
// Role *RoleVO `json:"roles"`
|
||||
//Status int8 `json:"status"`
|
||||
}
|
||||
|
||||
type MachineVO struct {
|
||||
//models.BaseModel
|
||||
Id *uint64 `json:"id"`
|
||||
ProjectId uint64 `json:"projectId"`
|
||||
ProjectName string `json:"projectName"`
|
||||
Name *string `json:"name"`
|
||||
Username *string `json:"username"`
|
||||
Ip *string `json:"ip"`
|
||||
Port *int `json:"port"`
|
||||
Status *int8 `json:"status"`
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
Creator *string `json:"creator"`
|
||||
CreatorId *int64 `json:"creatorId"`
|
||||
UpdateTime *time.Time `json:"updateTime"`
|
||||
Modifier *string `json:"modifier"`
|
||||
ModifierId *int64 `json:"modifierId"`
|
||||
HasCli bool `json:"hasCli" gorm:"-"`
|
||||
Remark *string `json:"remark"`
|
||||
}
|
||||
|
||||
type MachineScriptVO struct {
|
||||
Id *int64 `json:"id"`
|
||||
Name *string `json:"name"`
|
||||
Script *string `json:"script"`
|
||||
Type *int `json:"type"`
|
||||
Description *string `json:"description"`
|
||||
Params *string `json:"params"`
|
||||
MachineId *uint64 `json:"machineId"`
|
||||
}
|
||||
|
||||
type MachineFileVO struct {
|
||||
Id *int64 `json:"id"`
|
||||
Name *string `json:"name"`
|
||||
Path *string `json:"path"`
|
||||
Type *int `json:"type"`
|
||||
MachineId *uint64 `json:"machineId"`
|
||||
}
|
||||
|
||||
type MachineFileInfo struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Size int64 `json:"size"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type RoleVO struct {
|
||||
Id *int64
|
||||
Name *string
|
||||
}
|
||||
Reference in New Issue
Block a user