refactor: 后端包结构重构、去除无用的文件

This commit is contained in:
meilin.huang
2022-06-02 17:41:11 +08:00
parent 51d06ab206
commit b2dc9dff0b
234 changed files with 749 additions and 816 deletions

View File

@@ -0,0 +1,186 @@
package machine
import (
"errors"
"fmt"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/cache"
"mayfly-go/pkg/global"
"net"
"time"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
// 客户端信息
type Cli struct {
machine *entity.Machine
// ssh客户端
client *ssh.Client
sftpClient *sftp.Client
}
// 机器客户端连接缓存45分钟内没有访问则会被关闭
var cliCache = cache.NewTimedCache(45*time.Minute, 5*time.Second).
WithUpdateAccessTime(true).
OnEvicted(func(key interface{}, value interface{}) {
value.(*Cli).Close()
})
// 是否存在指定id的客户端连接
func HasCli(machineId uint64) bool {
if _, ok := cliCache.Get(machineId); ok {
return true
}
return false
}
// 删除指定机器客户端,并关闭客户端连接
func DeleteCli(id uint64) {
cliCache.Delete(id)
}
// 从缓存中获取客户端信息,不存在则回调获取机器信息函数,并新建
func GetCli(machineId uint64, getMachine func(uint64) *entity.Machine) (*Cli, error) {
cli, err := cliCache.ComputeIfAbsent(machineId, func(key interface{}) (interface{}, error) {
c, err := newClient(getMachine(machineId))
if err != nil {
return nil, err
}
return c, nil
})
if cli != nil {
return cli.(*Cli), err
}
return nil, err
}
//根据机器信息创建客户端对象
func newClient(machine *entity.Machine) (*Cli, error) {
if machine == nil {
return nil, errors.New("机器不存在")
}
global.Log.Infof("[%s]机器连接:%s:%d", machine.Name, machine.Ip, machine.Port)
cli := new(Cli)
cli.machine = machine
err := cli.connect()
if err != nil {
return nil, err
}
return cli, nil
}
//连接
func (c *Cli) connect() error {
// 如果已经有client则直接返回
if c.client != nil {
return nil
}
m := c.machine
config := ssh.ClientConfig{
User: m.Username,
Auth: []ssh.AuthMethod{ssh.Password(m.Password)},
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
Timeout: 5 * time.Second,
}
addr := fmt.Sprintf("%s:%d", m.Ip, m.Port)
sshClient, err := ssh.Dial("tcp", addr, &config)
if err != nil {
return err
}
c.client = sshClient
return nil
}
// 测试连接
func TestConn(m *entity.Machine) error {
config := ssh.ClientConfig{
User: m.Username,
Auth: []ssh.AuthMethod{ssh.Password(m.Password)},
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
Timeout: 5 * time.Second,
}
addr := fmt.Sprintf("%s:%d", m.Ip, m.Port)
sshClient, err := ssh.Dial("tcp", addr, &config)
if err != nil {
return err
}
defer sshClient.Close()
return nil
}
// 关闭client和并从缓存中移除
func (c *Cli) Close() {
m := c.machine
global.Log.Info(fmt.Sprintf("关闭机器客户端连接-> id: %d, name: %s, ip: %s", m.Id, m.Name, m.Ip))
if c.client != nil {
c.client.Close()
c.client = nil
}
if c.sftpClient != nil {
c.sftpClient.Close()
c.sftpClient = nil
}
}
// 获取sftp client
func (c *Cli) GetSftpCli() *sftp.Client {
if c.client == nil {
if err := c.connect(); err != nil {
panic(biz.NewBizErr("连接ssh失败" + err.Error()))
}
}
sftpclient := c.sftpClient
// 如果sftpClient为nil则连接
if sftpclient == nil {
sc, serr := sftp.NewClient(c.client)
if serr != nil {
panic(biz.NewBizErr("获取sftp client失败" + serr.Error()))
}
sftpclient = sc
c.sftpClient = sftpclient
}
return sftpclient
}
// 获取session
func (c *Cli) GetSession() (*ssh.Session, error) {
if c.client == nil {
if err := c.connect(); err != nil {
return nil, err
}
}
return c.client.NewSession()
}
//执行shell
//@param shell shell脚本命令
func (c *Cli) Run(shell string) (*string, error) {
session, err := c.GetSession()
if err != nil {
c.Close()
return nil, err
}
defer session.Close()
buf, rerr := session.CombinedOutput(shell)
if rerr != nil {
return nil, rerr
}
res := string(buf)
return &res, nil
}
func (c *Cli) GetMachine() *entity.Machine {
return c.machine
}

View File

@@ -0,0 +1,143 @@
package machine
import (
"fmt"
"mayfly-go/pkg/utils"
"strings"
"testing"
)
func TestSSH(t *testing.T) {
//ssh.ListenAndServe("148.70.36.197")
//cli := New("148.70.36.197", "root", "g..91mn#", 22)
////output, err := cli.Run("free -h")
////fmt.Printf("%v\n%v", output, err)
//err := cli.RunTerminal("tail -f /usr/local/java/logs/eatlife-info.log", os.Stdout, os.Stdin)
//fmt.Println(err)
res := "top - 17:14:07 up 5 days, 6:30, 2 users, load average: 0.03, 0.04, 0.05\nTasks: 101 total, 1 running, 100 sleeping, 0 stopped, 0 zombie\n%Cpu(s): 6.2 us, 0.0 sy, 0.0 ni, 93.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st\nKiB Mem : 1882012 total, 73892 free, 770360 used, 1037760 buff/cache\nKiB Swap: 0 total, 0 free, 0 used. 933492 avail Mem"
split := strings.Split(res, "\n")
//var firstLine string
//for i := 0; i < len(split); i++ {
// if i == 0 {
// val := strings.Split(split[i], "top -")[1]
// vals := strings.Split(val, ",")
//
// }
//}
firstLine := strings.Split(strings.Split(split[0], "top -")[1], ",")
// 17:14:07 up 5 days
up := strings.Trim(strings.Split(firstLine[0], "up")[1], " ") + firstLine[1]
// 2 users
users := strings.Split(strings.Trim(firstLine[2], " "), " ")[0]
// load average: 0.03
oneMinLa := strings.Trim(strings.Split(strings.Trim(firstLine[3], " "), ":")[1], " ")
fiveMinLa := strings.Trim(firstLine[4], " ")
fietMinLa := strings.Trim(firstLine[5], " ")
fmt.Println(firstLine, up, users, oneMinLa, fiveMinLa, fietMinLa)
tasks := Parse(strings.Split(split[1], "Tasks:")[1])
cpu := Parse(strings.Split(split[2], "%Cpu(s):")[1])
mem := Parse(strings.Split(split[3], "KiB Mem :")[1])
fmt.Println(tasks, cpu, mem)
}
func Parse(val string) map[string]string {
res := make(map[string]string)
vals := strings.Split(val, ",")
for i := 0; i < len(vals); i++ {
trimData := strings.Trim(vals[i], " ")
keyValue := strings.Split(trimData, " ")
res[keyValue[1]] = keyValue[0]
}
return res
}
func TestTemplateRev(t *testing.T) {
temp := "hello my name is {name} hahahaha lihaiba {age} years old {public}"
str := "hello my name is hmlhmlhm 慌慌信息 hahahaha lihaiba 15 years old private protected"
//temp1 := " top - {up}, {users} users, load average: {loadavg}"
//str1 := " top - 17:14:07 up 5 days, 6:30, 2 users, load average: 0.03, 0.04, 0.05"
//taskTemp := "Tasks: {total} total, {running} running, {sleeping} sleeping, {stopped} stopped, {zombie} zombie"
//taskVal := "Tasks: 101 total, 1 running, 100 sleeping, 0 stopped, 0 zombie"
//nameRunne := []rune(str)
//index := strings.Index(temp, "{")
//ei := strings.Index(temp, "}") + 1
//next := temp[ei:]
//key := temp[index+1 : ei-1]
//value := SubString(str, index, UnicodeIndex(str, next))
res := make(map[string]interface{})
utils.ReverStrTemplate(temp, str, res)
fmt.Println(res)
}
//func ReverStrTemplate(temp, str string, res map[string]string) {
// index := UnicodeIndex(temp, "{")
// ei := UnicodeIndex(temp, "}") + 1
// next := temp[ei:]
// nextContain := UnicodeIndex(next, "{")
// nextIndexValue := next
// if nextContain != -1 {
// nextIndexValue = SubString(next, 0, nextContain)
// }
// key := temp[index+1 : ei-1]
// // 如果后面没有内容了,则取字符串的长度即可
// var valueLastIndex int
// if nextIndexValue == "" {
// valueLastIndex = StrLen(str)
// } else {
// valueLastIndex = UnicodeIndex(str, nextIndexValue)
// }
// value := SubString(str, index, valueLastIndex)
// res[key] = value
//
// if nextContain != -1 {
// ReverStrTemplate(next, SubString(str, UnicodeIndex(str, value)+StrLen(value), StrLen(str)), res)
// }
//}
//
//func StrLen(str string) int {
// return len([]rune(str))
//}
//
//func SubString(str string, begin, end int) (substr string) {
// // 将字符串的转换成[]rune
// rs := []rune(str)
// lth := len(rs)
//
// // 简单的越界判断
// if begin < 0 {
// begin = 0
// }
// if begin >= lth {
// begin = lth
// }
// if end > lth {
// end = lth
// }
//
// // 返回子串
// return string(rs[begin:end])
//}
//
//func UnicodeIndex(str, substr string) int {
// // 子串在字符串的字节位置
// result := strings.Index(str, substr)
// if result >= 0 {
// // 获得子串之前的字符串并转换成[]byte
// prefix := []byte(str)[0:result]
// // 将子串之前的字符串转换成[]rune
// rs := []rune(string(prefix))
// // 获得子串之前的字符串的长度,便是子串在字符串的字符位置
// result = len(rs)
// }
//
// return result
//}
func TestTerminal(t *testing.T) {
// ioutil.ReadAll(file)
}

View File

@@ -0,0 +1,19 @@
package machine
const StatsShell = `
cat /proc/uptime
echo '-----'
/bin/hostname -f
echo '-----'
cat /proc/loadavg
echo '-----'
cat /proc/meminfo
echo '-----'
df -B1
echo '-----'
/sbin/ip -o addr
echo '-----'
/bin/cat /proc/net/dev
echo '-----'
top -b -n 1 | grep Cpu
`

View File

@@ -0,0 +1,277 @@
package machine
import (
"bufio"
"fmt"
"strconv"
"strings"
"time"
)
type FSInfo struct {
MountPoint string
Used uint64
Free uint64
}
type NetIntfInfo struct {
IPv4 string
IPv6 string
Rx uint64
Tx uint64
}
type CPUInfo struct {
User float32
Nice float32
System float32
Idle float32
Iowait float32
Irq float32
SoftIrq float32
Steal float32
Guest float32
}
type Stats struct {
Uptime string
Hostname string
Load1 string
Load5 string
Load10 string
RunningProcs string
TotalProcs string
MemTotal uint64
MemFree uint64
MemBuffers uint64
MemAvailable uint64
MemCached uint64
SwapTotal uint64
SwapFree uint64
FSInfos []FSInfo
NetIntf map[string]NetIntfInfo
CPU CPUInfo // or []CPUInfo to get all the cpu-core's stats?
}
func (c *Cli) GetAllStats() *Stats {
res, _ := c.Run(StatsShell)
infos := strings.Split(*res, "-----")
stats := new(Stats)
getUptime(infos[0], stats)
getHostname(infos[1], stats)
getLoad(infos[2], stats)
getMemInfo(infos[3], stats)
getFSInfo(infos[4], stats)
getInterfaces(infos[5], stats)
getInterfaceInfo(infos[6], stats)
getCPU(infos[7], stats)
return stats
}
func getUptime(uptime string, stats *Stats) (err error) {
parts := strings.Fields(uptime)
if len(parts) == 2 {
var upsecs float64
upsecs, err = strconv.ParseFloat(parts[0], 64)
if err != nil {
return
}
stats.Uptime = fmtUptime(time.Duration(upsecs * 1e9))
}
return
}
func fmtUptime(dur time.Duration) string {
dur = dur - (dur % time.Second)
var days int
for dur.Hours() > 24.0 {
days++
dur -= 24 * time.Hour
}
s1 := dur.String()
s2 := ""
if days > 0 {
s2 = fmt.Sprintf("%dd ", days)
}
for _, ch := range s1 {
s2 += string(ch)
if ch == 'h' || ch == 'm' {
s2 += " "
}
}
return s2
}
func getHostname(hostname string, stats *Stats) (err error) {
stats.Hostname = strings.TrimSpace(hostname)
return
}
func getLoad(loadInfo string, stats *Stats) (err error) {
parts := strings.Fields(loadInfo)
if len(parts) == 5 {
stats.Load1 = parts[0]
stats.Load5 = parts[1]
stats.Load10 = parts[2]
if i := strings.Index(parts[3], "/"); i != -1 {
stats.RunningProcs = parts[3][0:i]
if i+1 < len(parts[3]) {
stats.TotalProcs = parts[3][i+1:]
}
}
}
return
}
func getMemInfo(memInfo string, stats *Stats) (err error) {
// "/bin/cat /proc/meminfo"
scanner := bufio.NewScanner(strings.NewReader(memInfo))
for scanner.Scan() {
line := scanner.Text()
parts := strings.Fields(line)
if len(parts) == 3 {
val, err := strconv.ParseUint(parts[1], 10, 64)
if err != nil {
continue
}
val *= 1024
switch parts[0] {
case "MemTotal:":
stats.MemTotal = val
case "MemFree:":
stats.MemFree = val
case "Buffers:":
stats.MemBuffers = val
case "Cached:":
stats.MemCached = val
case "SwapTotal:":
stats.SwapTotal = val
case "SwapFree:":
stats.SwapFree = val
case "MemAvailable:":
stats.MemAvailable = val
}
}
}
return
}
func getFSInfo(fsInfo string, stats *Stats) (err error) {
// "/bin/df -B1"
scanner := bufio.NewScanner(strings.NewReader(fsInfo))
flag := 0
for scanner.Scan() {
line := scanner.Text()
parts := strings.Fields(line)
n := len(parts)
dev := n > 0 && strings.Index(parts[0], "/dev/") == 0
if n == 1 && dev {
flag = 1
} else if (n == 5 && flag == 1) || (n == 6 && dev) {
i := flag
flag = 0
used, err := strconv.ParseUint(parts[2-i], 10, 64)
if err != nil {
continue
}
free, err := strconv.ParseUint(parts[3-i], 10, 64)
if err != nil {
continue
}
stats.FSInfos = append(stats.FSInfos, FSInfo{
parts[5-i], used, free,
})
}
}
return
}
func getInterfaces(iInfo string, stats *Stats) (err error) {
// "/sbin/ip -o addr"
if stats.NetIntf == nil {
stats.NetIntf = make(map[string]NetIntfInfo)
}
scanner := bufio.NewScanner(strings.NewReader(iInfo))
for scanner.Scan() {
line := scanner.Text()
parts := strings.Fields(line)
if len(parts) >= 4 && (parts[2] == "inet" || parts[2] == "inet6") {
ipv4 := parts[2] == "inet"
intfname := parts[1]
if info, ok := stats.NetIntf[intfname]; ok {
if ipv4 {
info.IPv4 = parts[3]
} else {
info.IPv6 = parts[3]
}
stats.NetIntf[intfname] = info
} else {
info := NetIntfInfo{}
if ipv4 {
info.IPv4 = parts[3]
} else {
info.IPv6 = parts[3]
}
stats.NetIntf[intfname] = info
}
}
}
return
}
func getInterfaceInfo(iInfo string, stats *Stats) (err error) {
// /bin/cat /proc/net/dev
if stats.NetIntf == nil {
return
} // should have been here already
scanner := bufio.NewScanner(strings.NewReader(iInfo))
for scanner.Scan() {
line := scanner.Text()
parts := strings.Fields(line)
if len(parts) == 17 {
intf := strings.TrimSpace(parts[0])
intf = strings.TrimSuffix(intf, ":")
if info, ok := stats.NetIntf[intf]; ok {
rx, err := strconv.ParseUint(parts[1], 10, 64)
if err != nil {
continue
}
tx, err := strconv.ParseUint(parts[9], 10, 64)
if err != nil {
continue
}
info.Rx = rx
info.Tx = tx
stats.NetIntf[intf] = info
}
}
}
return
}
func getCPU(cpuInfo string, stats *Stats) (err error) {
// %Cpu(s): 6.1 us, 3.0 sy, 0.0 ni, 90.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
value := strings.Split(cpuInfo, ":")[1]
values := strings.Split(value, ",")
us, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[0]), " ")[0], 32)
stats.CPU.User = float32(us)
sy, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[1]), " ")[0], 32)
stats.CPU.System = float32(sy)
id, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[3]), " ")[0], 32)
stats.CPU.Idle = float32(id)
wa, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[4]), " ")[0], 32)
stats.CPU.Iowait = float32(wa)
return nil
}

View File

@@ -0,0 +1,195 @@
package machine
import (
"bytes"
"encoding/json"
"io"
"mayfly-go/pkg/global"
"sync"
"time"
"github.com/gorilla/websocket"
"golang.org/x/crypto/ssh"
)
type safeBuffer struct {
buffer bytes.Buffer
mu sync.Mutex
}
func (w *safeBuffer) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
return w.buffer.Write(p)
}
func (w *safeBuffer) Bytes() []byte {
w.mu.Lock()
defer w.mu.Unlock()
return w.buffer.Bytes()
}
func (w *safeBuffer) Reset() {
w.mu.Lock()
defer w.mu.Unlock()
w.buffer.Reset()
}
const (
wsMsgCmd = "cmd"
wsMsgResize = "resize"
)
type WsMsg struct {
Type string `json:"type"`
Msg string `json:"msg"`
Cols int `json:"cols"`
Rows int `json:"rows"`
}
type LogicSshWsSession struct {
stdinPipe io.WriteCloser
comboOutput *safeBuffer //ssh 终端混合输出
inputFilterBuff *safeBuffer //用来过滤输入的命令和ssh_filter配置对比的
session *ssh.Session
wsConn *websocket.Conn
}
func NewLogicSshWsSession(cols, rows int, cli *Cli, wsConn *websocket.Conn) (*LogicSshWsSession, error) {
sshSession, err := cli.GetSession()
if err != nil {
return nil, err
}
stdinP, err := sshSession.StdinPipe()
if err != nil {
return nil, err
}
comboWriter := new(safeBuffer)
inputBuf := new(safeBuffer)
//ssh.stdout and stderr will write output into comboWriter
sshSession.Stdout = comboWriter
sshSession.Stderr = comboWriter
modes := ssh.TerminalModes{
ssh.ECHO: 1, // disable echo
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := sshSession.RequestPty("xterm", rows, cols, modes); err != nil {
return nil, err
}
// Start remote shell
if err := sshSession.Shell(); err != nil {
return nil, err
}
return &LogicSshWsSession{
stdinPipe: stdinP,
comboOutput: comboWriter,
inputFilterBuff: inputBuf,
session: sshSession,
wsConn: wsConn,
}, nil
}
//Close 关闭
func (sws *LogicSshWsSession) Close() {
if sws.session != nil {
sws.session.Close()
}
if sws.comboOutput != nil {
sws.comboOutput = nil
}
}
func (sws *LogicSshWsSession) Start(quitChan chan bool) {
go sws.receiveWsMsg(quitChan)
go sws.sendComboOutput(quitChan)
}
//receiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
func (sws *LogicSshWsSession) receiveWsMsg(exitCh chan bool) {
wsConn := sws.wsConn
//tells other go routine quit
defer setQuit(exitCh)
for {
select {
case <-exitCh:
return
default:
//read websocket msg
_, wsData, err := wsConn.ReadMessage()
if err != nil {
if websocket.IsCloseError(err, websocket.CloseGoingAway, websocket.CloseNoStatusReceived) {
return
}
global.Log.Error("reading webSocket message failed: ", err)
return
}
//unmashal bytes into struct
msgObj := WsMsg{}
if err := json.Unmarshal(wsData, &msgObj); err != nil {
global.Log.Error("unmarshal websocket message failed", err)
}
switch msgObj.Type {
case wsMsgResize:
//handle xterm.js size change
if msgObj.Cols > 0 && msgObj.Rows > 0 {
if err := sws.session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
global.Log.Error("ssh pty change windows size failed")
}
}
case wsMsgCmd:
sws.sendWebsocketInputCommandToSshSessionStdinPipe([]byte(msgObj.Msg))
}
}
}
}
//sendWebsocketInputCommandToSshSessionStdinPipe
func (sws *LogicSshWsSession) sendWebsocketInputCommandToSshSessionStdinPipe(cmdBytes []byte) {
if _, err := sws.stdinPipe.Write(cmdBytes); err != nil {
global.Log.Error("ws cmd bytes write to ssh.stdin pipe failed")
}
}
func (sws *LogicSshWsSession) sendComboOutput(exitCh chan bool) {
wsConn := sws.wsConn
//todo 优化成一个方法
//tells other go routine quit
defer setQuit(exitCh)
//every 120ms write combine output bytes into websocket response
tick := time.NewTicker(time.Millisecond * time.Duration(60))
//for range time.Tick(120 * time.Millisecond){}
defer tick.Stop()
for {
select {
case <-tick.C:
if sws.comboOutput == nil {
return
}
bs := sws.comboOutput.Bytes()
if len(bs) > 0 {
err := wsConn.WriteMessage(websocket.TextMessage, bs)
if err != nil {
global.Log.Error("ssh sending combo output to webSocket failed")
}
sws.comboOutput.buffer.Reset()
}
case <-exitCh:
return
}
}
}
func (sws *LogicSshWsSession) Wait(quitChan chan bool) {
if err := sws.session.Wait(); err != nil {
setQuit(quitChan)
}
}
func setQuit(ch chan bool) {
ch <- true
}

View File

@@ -0,0 +1,67 @@
package persistence
import (
"fmt"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type dbRepo struct{}
var DbDao repository.Db = &dbRepo{}
// 分页获取数据库信息列表
func (d *dbRepo) GetDbList(condition *entity.Db, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
sql := "SELECT d.* FROM t_db d JOIN t_project_member pm ON d.project_id = pm.project_id WHERE 1 = 1 "
if condition.CreatorId != 0 {
// 使用创建者id模拟项目成员id
sql = fmt.Sprintf("%s AND pm.account_id = %d", sql, condition.CreatorId)
}
if condition.ProjectId != 0 {
sql = fmt.Sprintf("%s AND d.project_id = %d", sql, condition.ProjectId)
}
if condition.EnvId != 0 {
sql = fmt.Sprintf("%s AND d.env_id = %d", sql, condition.EnvId)
}
if condition.Host != "" {
sql = sql + " AND d.host LIKE '%" + condition.Host + "%'"
}
if condition.Database != "" {
sql = sql + " AND d.database LIKE '%" + condition.Database + "%'"
}
sql = sql + " ORDER BY d.create_time DESC"
return model.GetPageBySql(sql, pageParam, toEntity)
}
func (d *dbRepo) Count(condition *entity.Db) int64 {
return model.CountBy(condition)
}
// 根据条件获取账号信息
func (d *dbRepo) GetDb(condition *entity.Db, cols ...string) error {
return model.GetBy(condition, cols...)
}
// 根据id获取
func (d *dbRepo) GetById(id uint64, cols ...string) *entity.Db {
db := new(entity.Db)
if err := model.GetById(db, id, cols...); err != nil {
return nil
}
return db
}
func (d *dbRepo) Insert(db *entity.Db) {
biz.ErrIsNil(model.Insert(db), "新增数据库信息失败")
}
func (d *dbRepo) Update(db *entity.Db) {
biz.ErrIsNil(model.UpdateById(db), "更新数据库信息失败")
}
func (d *dbRepo) Delete(id uint64) {
model.DeleteById(new(entity.Db), id)
}

View File

@@ -0,0 +1,17 @@
package persistence
import (
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type dbSqlRepo struct{}
var DbSqlDao repository.DbSql = &dbSqlRepo{}
// 分页获取数据库信息列表
func (d *dbSqlRepo) DeleteBy(condition *entity.DbSql) {
biz.ErrIsNil(model.DeleteByCondition(condition), "删除sql失败")
}

View File

@@ -0,0 +1,45 @@
package persistence
import (
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type machineFileRepo struct{}
var MachineFileDao repository.MachineFile = &machineFileRepo{}
// 分页获取机器文件信息列表
func (m *machineFileRepo) GetPageList(condition *entity.MachineFile, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
return model.GetPage(pageParam, condition, toEntity, orderBy...)
}
// 根据条件获取账号信息
func (m *machineFileRepo) GetMachineFile(condition *entity.MachineFile, cols ...string) error {
return model.GetBy(condition, cols...)
}
// 根据id获取
func (m *machineFileRepo) GetById(id uint64, cols ...string) *entity.MachineFile {
ms := new(entity.MachineFile)
if err := model.GetById(ms, id, cols...); err != nil {
return nil
}
return ms
}
// 根据id获取
func (m *machineFileRepo) Delete(id uint64) {
biz.ErrIsNil(model.DeleteById(new(entity.MachineFile), id), "删除失败")
}
func (m *machineFileRepo) Create(entity *entity.MachineFile) {
model.Insert(entity)
}
func (m *machineFileRepo) UpdateById(entity *entity.MachineFile) {
model.UpdateById(entity)
}

View File

@@ -0,0 +1,59 @@
package persistence
import (
"fmt"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/model"
)
type machineRepo struct{}
var MachineDao repository.Machine = &machineRepo{}
// 分页获取机器信息列表
func (m *machineRepo) GetMachineList(condition *entity.Machine, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
sql := "SELECT m.* FROM t_machine m JOIN t_project_member pm ON m.project_id = pm.project_id WHERE 1 = 1 "
if condition.CreatorId != 0 {
// 使用创建者id模拟项目成员id
sql = fmt.Sprintf("%s AND pm.account_id = %d", sql, condition.CreatorId)
}
if condition.ProjectId != 0 {
sql = fmt.Sprintf("%s AND m.project_id = %d", sql, condition.ProjectId)
}
if condition.Ip != "" {
sql = sql + " AND m.ip LIKE '%" + condition.Ip + "%'"
}
if condition.Name != "" {
sql = sql + " AND m.name LIKE '%" + condition.Name + "%'"
}
sql = sql + " ORDER BY m.project_id, m.create_time DESC"
return model.GetPageBySql(sql, pageParam, toEntity)
}
func (m *machineRepo) Count(condition *entity.Machine) int64 {
return model.CountBy(condition)
}
// 根据条件获取账号信息
func (m *machineRepo) GetMachine(condition *entity.Machine, cols ...string) error {
return model.GetBy(condition, cols...)
}
// 根据id获取
func (m *machineRepo) GetById(id uint64, cols ...string) *entity.Machine {
machine := new(entity.Machine)
if err := model.GetById(machine, id, cols...); err != nil {
return nil
}
return machine
}
func (m *machineRepo) Create(entity *entity.Machine) {
model.Insert(entity)
}
func (m *machineRepo) UpdateById(entity *entity.Machine) {
model.UpdateById(entity)
}

View File

@@ -0,0 +1,45 @@
package persistence
import (
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type machineScriptRepo struct{}
var MachineScriptDao repository.MachineScript = &machineScriptRepo{}
// 分页获取机器信息列表
func (m *machineScriptRepo) GetPageList(condition *entity.MachineScript, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
return model.GetPage(pageParam, condition, toEntity, orderBy...)
}
// 根据条件获取账号信息
func (m *machineScriptRepo) GetMachineScript(condition *entity.MachineScript, cols ...string) error {
return model.GetBy(condition, cols...)
}
// 根据id获取
func (m *machineScriptRepo) GetById(id uint64, cols ...string) *entity.MachineScript {
ms := new(entity.MachineScript)
if err := model.GetById(ms, id, cols...); err != nil {
return nil
}
return ms
}
// 根据id获取
func (m *machineScriptRepo) Delete(id uint64) {
biz.ErrIsNil(model.DeleteById(new(entity.MachineScript), id), "删除失败")
}
func (m *machineScriptRepo) Create(entity *entity.MachineScript) {
model.Insert(entity)
}
func (m *machineScriptRepo) UpdateById(entity *entity.MachineScript) {
model.UpdateById(entity)
}

View File

@@ -0,0 +1,61 @@
package persistence
import (
"fmt"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type mongoRepo struct{}
var MongoDao repository.Mongo = &mongoRepo{}
// 分页获取数据库信息列表
func (d *mongoRepo) GetList(condition *entity.Mongo, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
sql := "SELECT d.* FROM t_mongo d JOIN t_project_member pm ON d.project_id = pm.project_id WHERE 1 = 1 "
if condition.CreatorId != 0 {
// 使用创建者id模拟项目成员id
sql = fmt.Sprintf("%s AND pm.account_id = %d", sql, condition.CreatorId)
}
if condition.ProjectId != 0 {
sql = fmt.Sprintf("%s AND d.project_id = %d", sql, condition.ProjectId)
}
if condition.EnvId != 0 {
sql = fmt.Sprintf("%s AND d.env_id = %d", sql, condition.EnvId)
}
sql = sql + " ORDER BY d.create_time DESC"
return model.GetPageBySql(sql, pageParam, toEntity)
}
func (d *mongoRepo) Count(condition *entity.Mongo) int64 {
return model.CountBy(condition)
}
// 根据条件获取
func (d *mongoRepo) Get(condition *entity.Mongo, cols ...string) error {
return model.GetBy(condition, cols...)
}
// 根据id获取
func (d *mongoRepo) GetById(id uint64, cols ...string) *entity.Mongo {
db := new(entity.Mongo)
if err := model.GetById(db, id, cols...); err != nil {
return nil
}
return db
}
func (d *mongoRepo) Insert(db *entity.Mongo) {
biz.ErrIsNil(model.Insert(db), "新增mongo信息失败")
}
func (d *mongoRepo) Update(db *entity.Mongo) {
biz.ErrIsNil(model.UpdateById(db), "更新mongo信息失败")
}
func (d *mongoRepo) Delete(id uint64) {
model.DeleteById(new(entity.Mongo), id)
}

View File

@@ -0,0 +1,24 @@
package persistence
import (
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type projectEnvRepo struct{}
var ProjectEnvRepo repository.ProjectEnv = &projectEnvRepo{}
func (p *projectEnvRepo) ListEnv(condition *entity.ProjectEnv, toEntity interface{}, orderBy ...string) {
model.ListByOrder(condition, toEntity, orderBy...)
}
func (p *projectEnvRepo) Save(entity *entity.ProjectEnv) {
biz.ErrIsNilAppendErr(model.Insert(entity), "保存环境失败:%s")
}
func (p *projectEnvRepo) DeleteEnvs(projectId uint64) {
model.DeleteByCondition(&entity.ProjectEnv{ProjectId: projectId})
}

View File

@@ -0,0 +1,36 @@
package persistence
import (
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type projectMemeberRepo struct{}
var ProjectMemberRepo repository.ProjectMemeber = &projectMemeberRepo{}
func (p *projectMemeberRepo) ListMemeber(condition *entity.ProjectMember, toEntity interface{}, orderBy ...string) {
model.ListByOrder(condition, toEntity, orderBy...)
}
func (p *projectMemeberRepo) Save(pm *entity.ProjectMember) {
biz.ErrIsNilAppendErr(model.Insert(pm), "保存项目成员失败:%s")
}
func (p *projectMemeberRepo) GetPageList(condition *entity.ProjectMember, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
return model.GetPage(pageParam, condition, toEntity, orderBy...)
}
func (p *projectMemeberRepo) DeleteByPidMid(projectId, accountId uint64) {
model.DeleteByCondition(&entity.ProjectMember{ProjectId: projectId, AccountId: accountId})
}
func (p *projectMemeberRepo) DeleteMems(projectId uint64) {
model.DeleteByCondition(&entity.ProjectMember{ProjectId: projectId})
}
func (p *projectMemeberRepo) IsExist(projectId, accountId uint64) bool {
return model.CountBy(&entity.ProjectMember{ProjectId: projectId, AccountId: accountId}) > 0
}

View File

@@ -0,0 +1,36 @@
package persistence
import (
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type projectRepo struct{}
var ProjectRepo repository.Project = &projectRepo{}
func (p *projectRepo) GetPageList(condition *entity.Project, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
return model.GetPage(pageParam, condition, toEntity, orderBy...)
}
func (p *projectRepo) Count(condition *entity.Project) int64 {
return model.CountBy(condition)
}
func (p *projectRepo) GetByIdIn(ids []uint64, toEntity interface{}, orderBy ...string) {
model.GetByIdIn(new(entity.Project), toEntity, ids, orderBy...)
}
func (p *projectRepo) Save(project *entity.Project) {
biz.ErrIsNil(model.Insert(project), "保存项目失败")
}
func (p *projectRepo) Update(project *entity.Project) {
biz.ErrIsNil(model.UpdateById(project), "更新项目信息")
}
func (p *projectRepo) Delete(id uint64) {
model.DeleteById(new(entity.Project), id)
}

View File

@@ -0,0 +1,62 @@
package persistence
import (
"fmt"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
)
type redisRepo struct{}
var RedisDao repository.Redis = &redisRepo{}
// 分页获取机器信息列表
func (r *redisRepo) GetRedisList(condition *entity.Redis, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
sql := "SELECT d.* FROM t_redis d JOIN t_project_member pm ON d.project_id = pm.project_id WHERE 1 = 1 "
if condition.CreatorId != 0 {
// 使用创建者id模拟项目成员id
sql = fmt.Sprintf("%s AND pm.account_id = %d", sql, condition.CreatorId)
}
if condition.ProjectId != 0 {
sql = fmt.Sprintf("%s AND d.project_id = %d", sql, condition.ProjectId)
}
if condition.EnvId != 0 {
sql = fmt.Sprintf("%s AND d.env_id = %d", sql, condition.EnvId)
}
if condition.Host != "" {
sql = sql + " AND d.host LIKE '%" + condition.Host + "%'"
}
sql = sql + " ORDER BY d.create_time DESC"
return model.GetPageBySql(sql, pageParam, toEntity)
}
func (r *redisRepo) Count(condition *entity.Redis) int64 {
return model.CountBy(condition)
}
// 根据id获取
func (r *redisRepo) GetById(id uint64, cols ...string) *entity.Redis {
rd := new(entity.Redis)
if err := model.GetById(rd, id, cols...); err != nil {
return nil
}
return rd
}
func (r *redisRepo) GetRedis(condition *entity.Redis, cols ...string) error {
return model.GetBy(condition, cols...)
}
func (r *redisRepo) Insert(redis *entity.Redis) {
biz.ErrIsNilAppendErr(model.Insert(redis), "新增失败: %s")
}
func (r *redisRepo) Update(redis *entity.Redis) {
biz.ErrIsNilAppendErr(model.UpdateById(redis), "更新失败: %s")
}
func (r *redisRepo) Delete(id uint64) {
biz.ErrIsNilAppendErr(model.DeleteById(new(entity.Redis), id), "删除失败: %s")
}

View File

@@ -0,0 +1,27 @@
package scheduler
func init() {
SaveMachineMonitor()
}
func SaveMachineMonitor() {
AddFun("@every 60s", func() {
// for _, m := range models.GetNeedMonitorMachine() {
// m := m
// go func() {
// cli, err := machine.GetCli(uint64(utils.GetInt4Map(m, "id")))
// if err != nil {
// mlog.Log.Error("获取客户端失败:", err.Error())
// return
// }
// mm := cli.GetMonitorInfo()
// if mm != nil {
// err := model.Insert(mm)
// if err != nil {
// mlog.Log.Error("保存机器监控信息失败: ", err.Error())
// }
// }
// }()
// }
})
}

View File

@@ -0,0 +1,33 @@
package scheduler
import (
"mayfly-go/pkg/biz"
"github.com/robfig/cron/v3"
)
var cronService = cron.New()
func Start() {
cronService.Start()
}
func Stop() {
cronService.Stop()
}
func Remove(id cron.EntryID) {
cronService.Remove(id)
}
func GetCron() *cron.Cron {
return cronService
}
func AddFun(spec string, cmd func()) cron.EntryID {
id, err := cronService.AddFunc(spec, cmd)
if err != nil {
panic(biz.NewBizErr("添加任务失败:" + err.Error()))
}
return id
}