3.0.0
This commit is contained in:
parent
8379624581
commit
ed35ddc388
|
@ -45,9 +45,11 @@ _test
|
|||
/src/modules/transfer/transfer
|
||||
/src/modules/tsdb/tsdb
|
||||
/src/modules/monapi/monapi
|
||||
/src/modules/rdb/rdb
|
||||
|
||||
/web/node_modules
|
||||
/web/.cache-loader
|
||||
/web/yarn.lock
|
||||
Makefile
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
#!/bin/bash -x
|
||||
|
||||
# release version
|
||||
version=3.0.0
|
||||
|
||||
CWD=$(cd $(dirname $0)/; pwd)
|
||||
cd $CWD
|
||||
|
||||
usage()
|
||||
{
|
||||
echo $"Usage: $0 {start|stop|restart|status|build|pack} <module>"
|
||||
exit 0
|
||||
}
|
||||
|
||||
start_all()
|
||||
{
|
||||
test -x n9e-rdb && start rdb
|
||||
test -x n9e-transfer && start transfer
|
||||
test -x n9e-tsdb && start tsdb
|
||||
test -x n9e-index && start index
|
||||
test -x n9e-judge && start judge
|
||||
test -x n9e-monapi && start monapi
|
||||
test -x n9e-job && start job
|
||||
test -x n9e-ams && start ams
|
||||
test -x n9e-agent && start agent
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
mod=$1
|
||||
if [ "x${mod}" = "x" ]; then
|
||||
usage
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "x${mod}" = "xall" ]; then
|
||||
start_all
|
||||
return
|
||||
fi
|
||||
|
||||
binfile=n9e-${mod}
|
||||
|
||||
if [ ! -f $binfile ]; then
|
||||
echo "file[$binfile] not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -gt 0 ]; then
|
||||
echo "${mod} already started"
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p logs/$mod
|
||||
nohup $CWD/$binfile &> logs/${mod}/stdout.log &
|
||||
|
||||
for((i=1;i<=15;i++)); do
|
||||
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -gt 0 ]; then
|
||||
echo "${mod} started"
|
||||
return
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
echo "cannot start ${mod}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
stop_all()
|
||||
{
|
||||
test -x n9e-monapi && stop monapi
|
||||
test -x n9e-transfer && stop transfer
|
||||
test -x n9e-tsdb && stop tsdb
|
||||
test -x n9e-index && stop index
|
||||
test -x n9e-judge && stop judge
|
||||
test -x n9e-agent && stop agent
|
||||
test -x n9e-ams && stop ams
|
||||
test -x n9e-job && stop job
|
||||
test -x n9e-rdb && stop rdb
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
mod=$1
|
||||
if [ "x${mod}" = "x" ]; then
|
||||
usage
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "x${mod}" = "xall" ]; then
|
||||
stop_all
|
||||
return
|
||||
fi
|
||||
|
||||
binfile=n9e-${mod}
|
||||
|
||||
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -eq 0 ]; then
|
||||
echo "${mod} already stopped"
|
||||
return
|
||||
fi
|
||||
|
||||
ps aux|grep -v grep|grep -v control|grep "$binfile"|awk '{print $2}'|xargs kill
|
||||
for((i=1;i<=15;i++)); do
|
||||
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -eq 0 ]; then
|
||||
echo "${mod} stopped"
|
||||
return
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
echo "cannot stop $mod"
|
||||
exit 1
|
||||
}
|
||||
|
||||
restart()
|
||||
{
|
||||
mod=$1
|
||||
if [ "x${mod}" = "x" ]; then
|
||||
usage
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "x${mod}" = "xall" ]; then
|
||||
stop_all
|
||||
start_all
|
||||
return
|
||||
fi
|
||||
|
||||
stop $mod
|
||||
start $mod
|
||||
|
||||
status
|
||||
}
|
||||
|
||||
status()
|
||||
{
|
||||
ps aux|grep -v grep|grep "n9e"
|
||||
}
|
||||
|
||||
build_one()
|
||||
{
|
||||
mod=$1
|
||||
go build -ldflags "-X main.version=${version}" -o n9e-${mod} src/modules/${mod}/${mod}.go
|
||||
}
|
||||
|
||||
build_docker()
|
||||
{
|
||||
mod=$1
|
||||
go build -ldflags "-X main.version=${version}" -o bin/n9e-${mod} src/modules/${mod}/${mod}.go
|
||||
}
|
||||
|
||||
build()
|
||||
{
|
||||
export GO111MODULE=on
|
||||
|
||||
mod=$1
|
||||
if [ "x${mod}" = "x" ]; then
|
||||
build_one monapi
|
||||
build_one transfer
|
||||
build_one index
|
||||
build_one judge
|
||||
build_one agent
|
||||
build_one tsdb
|
||||
build_one rdb
|
||||
build_one ams
|
||||
build_one job
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "x${mod}" = "xdocker" ]; then
|
||||
build_docker monapi
|
||||
build_docker transfer
|
||||
build_docker index
|
||||
build_docker judge
|
||||
build_docker agent
|
||||
build_docker tsdb
|
||||
build_docker rdb
|
||||
build_docker ams
|
||||
build_docker job
|
||||
return
|
||||
fi
|
||||
|
||||
build_one $mod
|
||||
}
|
||||
|
||||
reload()
|
||||
{
|
||||
mod=$1
|
||||
if [ "x${mod}" = "x" ]; then
|
||||
echo "arg: <mod> is necessary"
|
||||
return
|
||||
fi
|
||||
|
||||
build_one $mod
|
||||
restart $mod
|
||||
}
|
||||
|
||||
pack()
|
||||
{
|
||||
v=$1
|
||||
if [ "x${v}" = "x" ]; then
|
||||
v=$(date +%Y-%m-%d-%H-%M-%S)
|
||||
fi
|
||||
|
||||
tar zcvf n9e-$v.tar.gz control sql pub etc/service etc/nginx.conf etc/mysql.yml etc/address.yml \
|
||||
n9e-agent etc/agent.yml \
|
||||
n9e-tsdb etc/tsdb.yml \
|
||||
n9e-index etc/index.yml \
|
||||
n9e-judge etc/judge.yml \
|
||||
n9e-transfer etc/transfer.yml \
|
||||
n9e-monapi etc/monapi.yml
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start $2
|
||||
;;
|
||||
stop)
|
||||
stop $2
|
||||
;;
|
||||
restart)
|
||||
restart $2
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
build)
|
||||
build $2
|
||||
;;
|
||||
reload)
|
||||
reload $2
|
||||
;;
|
||||
pack)
|
||||
pack $2
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
esac
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
rdb:
|
||||
http: 0.0.0.0:8000
|
||||
|
||||
ams:
|
||||
http: 0.0.0.0:8002
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
job:
|
||||
http: 0.0.0.0:8004
|
||||
rpc: 0.0.0.0:8005
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
monapi:
|
||||
http: 0.0.0.0:8006
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
transfer:
|
||||
http: 0.0.0.0:8008
|
||||
rpc: 0.0.0.0:8009
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
tsdb:
|
||||
http: 0.0.0.0:8010
|
||||
rpc: 0.0.0.0:8011
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
index:
|
||||
http: 0.0.0.0:8012
|
||||
rpc: 0.0.0.0:8013
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
judge:
|
||||
http: 0.0.0.0:8014
|
||||
rpc: 0.0.0.0:8015
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
agent:
|
||||
http: 0.0.0.0:2080
|
|
@ -0,0 +1,65 @@
|
|||
logger:
|
||||
dir: logs/agent
|
||||
level: INFO
|
||||
keepHours: 24
|
||||
|
||||
enable:
|
||||
mon: false
|
||||
job: false
|
||||
report: false
|
||||
|
||||
job:
|
||||
metadir: ./meta
|
||||
interval: 2
|
||||
|
||||
report:
|
||||
# 调用ams的接口上报数据,需要ams的token
|
||||
token: ams-builtin-token
|
||||
|
||||
# 上报周期,单位是秒
|
||||
interval: 10
|
||||
|
||||
# physical:物理机,virtual:虚拟机,container:容器,switch:交换机
|
||||
cate: physical
|
||||
|
||||
# 使用哪个字段作为唯一KEY,即作为where条件更新对应记录
|
||||
# 一般使用sn,虚机的话把uuid当做sn即可,不同IaaS平台获取方式可能不同
|
||||
uniqkey: sn
|
||||
|
||||
# 如果是虚拟机,应该是获取uuid
|
||||
sn: dmidecode -s system-serial-number | tail -n 1
|
||||
|
||||
fields:
|
||||
cpu: cat /proc/cpuinfo | grep processor | wc -l
|
||||
mem: cat /proc/meminfo | grep MemTotal | awk '{printf "%dGi", $2/1024/1024}'
|
||||
disk: df -m | grep '/dev/' | grep -v '/var/lib' | grep -v tmpfs | awk '{sum += $2};END{printf "%dGi", sum/1024}'
|
||||
|
||||
sys:
|
||||
# timeout in ms
|
||||
# interval in second
|
||||
timeout: 1000
|
||||
interval: 20
|
||||
ifacePrefix:
|
||||
- eth
|
||||
- em
|
||||
- ens
|
||||
|
||||
# ignore disk mount point
|
||||
mountIgnore:
|
||||
prefix:
|
||||
- /var/lib
|
||||
- /run
|
||||
# collect anyway
|
||||
exclude: []
|
||||
|
||||
ignoreMetrics:
|
||||
- cpu.core.idle
|
||||
- cpu.core.util
|
||||
- cpu.core.sys
|
||||
- cpu.core.user
|
||||
- cpu.core.nice
|
||||
- cpu.core.guest
|
||||
- cpu.core.irq
|
||||
- cpu.core.softirq
|
||||
- cpu.core.iowait
|
||||
- cpu.core.steal
|
|
@ -0,0 +1,12 @@
|
|||
logger:
|
||||
dir: logs/ams
|
||||
level: INFO
|
||||
keepHours: 24
|
||||
|
||||
http:
|
||||
mode: release
|
||||
cookieDomain: ""
|
||||
cookieName: ecmc-user
|
||||
|
||||
tokens:
|
||||
- ams-builtin-token
|
|
@ -0,0 +1,16 @@
|
|||
- system: 资产管理系统
|
||||
groups:
|
||||
- title: 主机设备
|
||||
ops:
|
||||
- en: ams_host_mgr_menu
|
||||
cn: 主机设备管理菜单
|
||||
- en: ams_host_delete
|
||||
cn: 主机设备删除
|
||||
- en: ams_host_modify
|
||||
cn: 主机设备信息修改
|
||||
- title: 网络设备
|
||||
ops:
|
||||
- en: ams_netware_mgr_menu
|
||||
cn: 网络设备管理菜单
|
||||
- en: ams_netware_modify
|
||||
cn: 网络设备信息修改
|
|
@ -0,0 +1,9 @@
|
|||
# 用来做心跳,给服务端上报本机ip
|
||||
ip:
|
||||
specify: ""
|
||||
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|head -n 1
|
||||
|
||||
# MON、JOB的客户端拿来做本机标识
|
||||
ident:
|
||||
specify: ""
|
||||
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|head -n 1
|
|
@ -0,0 +1,4 @@
|
|||
logger:
|
||||
dir: logs/index
|
||||
level: WARNING
|
||||
keepHours: 2
|
|
@ -0,0 +1,15 @@
|
|||
logger:
|
||||
dir: logs/job
|
||||
level: INFO
|
||||
keepHours: 24
|
||||
|
||||
http:
|
||||
mode: release
|
||||
cookieDomain: ""
|
||||
cookieName: ecmc-user
|
||||
|
||||
output:
|
||||
# database | remote
|
||||
comeFrom: database
|
||||
remotePort: 2080
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
query:
|
||||
connTimeout: 1000
|
||||
callTimeout: 2000
|
||||
indexCallTimeout: 2000
|
||||
|
||||
redis:
|
||||
addrs:
|
||||
- 127.0.0.1:6379
|
||||
pass: ""
|
||||
# timeout:
|
||||
# conn: 500
|
||||
# read: 3000
|
||||
# write: 3000
|
||||
|
||||
logger:
|
||||
dir: logs/judge
|
||||
level: WARNING
|
||||
keepHours: 2
|
|
@ -0,0 +1,66 @@
|
|||
- system: 用户资源库
|
||||
groups:
|
||||
- title: 人员授权
|
||||
ops:
|
||||
- en: rdb_perm_grant
|
||||
cn: 权限分配
|
||||
- title: 节点类操作
|
||||
ops:
|
||||
- en: rdb_node_create
|
||||
cn: 创建节点
|
||||
- en: rdb_node_modify
|
||||
cn: 修改节点
|
||||
- en: rdb_node_delete
|
||||
cn: 删除节点
|
||||
- title: 资源类操作
|
||||
ops:
|
||||
- en: rdb_resource_view
|
||||
cn: 资源信息查看
|
||||
- en: rdb_resource_bind
|
||||
cn: 资源挂载节点
|
||||
- en: rdb_resource_unbind
|
||||
cn: 资源解挂节点
|
||||
- en: rdb_resource_modify
|
||||
cn: 资源信息修改
|
||||
- system: 任务执行中心
|
||||
groups:
|
||||
- title: 任务模板相关
|
||||
ops:
|
||||
- en: job_tpl_view
|
||||
cn: 查看任务模板
|
||||
- en: job_tpl_create
|
||||
cn: 创建任务模板
|
||||
- en: job_tpl_modify
|
||||
cn: 修改任务模板
|
||||
- en: job_tpl_delete
|
||||
cn: 删除任务模板
|
||||
- title: 任务执行相关
|
||||
ops:
|
||||
- en: task_run_use_root_account
|
||||
cn: 使用root账号运行脚本
|
||||
- en: task_run_use_gene_account
|
||||
cn: 使用普通账号运行脚本
|
||||
- system: 监控告警系统
|
||||
groups:
|
||||
- title: 告警策略
|
||||
ops:
|
||||
- en: mon_stra_write
|
||||
cn: 告警策略配置权限
|
||||
- title: 采集策略
|
||||
ops:
|
||||
- en: mon_collect_write
|
||||
cn: 采集策略配置权限
|
||||
- title: 大屏操作
|
||||
ops:
|
||||
- en: mon_screen_write
|
||||
cn: 监控大屏配置权限
|
||||
- en: mon_screen_read
|
||||
cn: 监控大屏查看权限
|
||||
- title: 指标计算
|
||||
ops:
|
||||
- en: mon_aggr_write
|
||||
cn: 指标计算配置权限
|
||||
- title: 告警历史
|
||||
ops:
|
||||
- en: mon_event_write
|
||||
cn: 告警历史屏蔽、认领、忽略
|
|
@ -0,0 +1,237 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>夜莺告警通知</title>
|
||||
<style type="text/css">
|
||||
.wrapper {
|
||||
background-color: #f8f8f8;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
}
|
||||
.main {
|
||||
width: 600px;
|
||||
padding: 30px;
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
font-size: 12px;
|
||||
font-family: verdana,'Microsoft YaHei',Consolas,'Deja Vu Sans Mono','Bitstream Vera Sans Mono';
|
||||
}
|
||||
header {
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
header .title {
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
margin: 0;
|
||||
}
|
||||
header .sub-desc {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
hr {
|
||||
margin: 20px 0;
|
||||
height: 0;
|
||||
border: none;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
em {
|
||||
font-weight: 600;
|
||||
}
|
||||
table {
|
||||
margin: 20px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table tbody tr{
|
||||
font-weight: 200;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.succ {
|
||||
background-color: green;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.fail {
|
||||
background-color: red;
|
||||
color: white;
|
||||
}
|
||||
|
||||
table tbody tr th {
|
||||
width: 80px;
|
||||
text-align: right;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
.body {
|
||||
margin-top: 24px;
|
||||
}
|
||||
.body-text {
|
||||
color: #666666;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
.body-extra {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
.body-extra.text-right a {
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
}
|
||||
.body-extra.text-right a:hover {
|
||||
color: #666;
|
||||
}
|
||||
.button {
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
background: #2D77EE;
|
||||
line-height: 50px;
|
||||
font-size: 20px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
.button:hover {
|
||||
background: rgb(25, 115, 255);
|
||||
border-color: rgb(25, 115, 255);
|
||||
color: #fff;
|
||||
}
|
||||
footer {
|
||||
margin-top: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
.footer-logo {
|
||||
text-align: right;
|
||||
}
|
||||
.footer-logo-image {
|
||||
width: 108px;
|
||||
height: 27px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.copyright {
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="main">
|
||||
<header>
|
||||
<h3 class="title">{{.Sname}}</h3>
|
||||
<p class="sub-desc"></p>
|
||||
</header>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="body">
|
||||
<div class="body-text">
|
||||
<div style="color: red">
|
||||
{{if .IsUpgrade}}
|
||||
注意,告警已触发升级!
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table cellspacing="0" cellpadding="0" border="0">
|
||||
<tbody>
|
||||
{{if .IsAlert}}
|
||||
<tr class="fail">
|
||||
<th>级别状态:</th>
|
||||
<td>{{.Status}}</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr class="succ">
|
||||
<th>级别状态:</th>
|
||||
<td>{{.Status}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
{{if .IsMachineDep}}
|
||||
<tr>
|
||||
<th>告警设备:</th>
|
||||
<td>{{.Endpoint}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>挂载节点:</th>
|
||||
<td>
|
||||
{{range .Bindings}}
|
||||
{{.}}<br />
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr>
|
||||
<th>所属节点:</th>
|
||||
<td>{{.CurNodePath}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
<tr>
|
||||
<th>监控指标:</th>
|
||||
<td>{{.Metric}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>tags:</th>
|
||||
<td>{{.Tags}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>当前值:</th>
|
||||
<td>{{.Value}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>报警说明:</th>
|
||||
<td>
|
||||
{{.Info}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>触发时间:</th>
|
||||
<td>
|
||||
{{.Etime}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>报警详情:</th>
|
||||
<td>{{.Elink}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>报警策略:</th>
|
||||
<td>{{.Slink}}</td>
|
||||
</tr>
|
||||
{{if .HasClaim}}
|
||||
<tr>
|
||||
<th>认领报警:</th>
|
||||
<td>{{.Clink}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
|
||||
<footer>
|
||||
<div class="footer-logo">
|
||||
<a href="https://n9e.didiyun.com">
|
||||
<img src="https://s3-gz01.didistatic.com/n9e-pub/image/n9e-logo-bg-white.png" class="footer-logo-image" alt="">
|
||||
</a>
|
||||
</div>
|
||||
<div class="copyright" style="font-style: italic">
|
||||
我们希望与您一起,将监控这个事情,做到极致!
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
tokens:
|
||||
- monapi-internal-third-module-pass-fjsdi
|
||||
logger:
|
||||
dir: logs/monapi
|
||||
level: WARNING
|
||||
keepHours: 2
|
||||
region:
|
||||
- default
|
||||
# read alert from redis
|
||||
redis:
|
||||
addr: 127.0.0.1:6379
|
||||
pass: 1234
|
||||
# timeout:
|
||||
# conn: 500
|
||||
# read: 3000
|
||||
# write: 3000
|
||||
|
||||
notify:
|
||||
p1: ["voice", "sms", "mail", "im"]
|
||||
p2: ["sms", "mail", "im"]
|
||||
p3: ["mail", "im"]
|
||||
|
||||
# addresses accessible using browser
|
||||
link:
|
||||
stra: http://ecmc.com/mon/strategy/%v
|
||||
event: http://ecmc.com/mon/history/his/%v
|
||||
claim: http://ecmc.com/mon/history/cur/%v
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
rdb:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_rdb?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
||||
ams:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_ams?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
||||
job:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_job?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
||||
mon:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_mon?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
||||
hbs:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_hbs?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
|
@ -0,0 +1,76 @@
|
|||
logger:
|
||||
dir: logs/rdb
|
||||
level: INFO
|
||||
keepHours: 24
|
||||
|
||||
http:
|
||||
mode: release
|
||||
cookieDomain: ""
|
||||
cookieName: ecmc-user
|
||||
|
||||
sso:
|
||||
enable: true
|
||||
ssoAddr: "http://10.86.76.13:8071"
|
||||
redirectURL: "http://10.86.76.13:8072/api/rdb/auth/callback"
|
||||
clientId: ""
|
||||
clientSecret: ""
|
||||
apiKey: ""
|
||||
|
||||
tokens:
|
||||
- uic-builtin-token
|
||||
- hsp-builtin-token
|
||||
- rdb-builtin-token
|
||||
|
||||
# for ldap authorization
|
||||
ldap:
|
||||
host: "ldap.example.org"
|
||||
port: 389
|
||||
baseDn: "dc=example,dc=org"
|
||||
# AD: manange@example.org
|
||||
bindUser: "cn=manager,dc=example,dc=org"
|
||||
bindPass: "*******"
|
||||
# openldap: (&(uid=%s))
|
||||
# AD: (&(sAMAccountName=%s))
|
||||
authFilter: "(&(uid=%s))"
|
||||
attributes:
|
||||
dispname: "cn"
|
||||
email: "mail"
|
||||
phone: "mobile"
|
||||
im: ""
|
||||
coverAttributes: false
|
||||
autoRegist: true
|
||||
tls: false
|
||||
startTLS: false
|
||||
|
||||
# as queue for sender
|
||||
redis:
|
||||
enable: false
|
||||
addr: 127.0.0.1:6379
|
||||
pass: ""
|
||||
idle: 5
|
||||
timeout:
|
||||
conn: 500
|
||||
read: 3000
|
||||
write: 3000
|
||||
|
||||
sender:
|
||||
mail:
|
||||
# three choice: smtp|shell|api
|
||||
way: smtp
|
||||
worker: 10
|
||||
api: http://127.0.0.1:2008/mail
|
||||
sms:
|
||||
# two choice: shell|api
|
||||
way: api
|
||||
worker: 10
|
||||
api: http://127.0.0.1:2008/sms
|
||||
voice:
|
||||
# two choice: shell|api
|
||||
way: shell
|
||||
worker: 10
|
||||
api: http://127.0.0.1:2008/voice
|
||||
im:
|
||||
# two choice: shell|api
|
||||
way: shell
|
||||
worker: 10
|
||||
api: http://127.0.0.1:2008/im
|
|
@ -0,0 +1,14 @@
|
|||
{{if .IsUpgrade}}注意,告警已触发升级!{{end}}
|
||||
级别状态:{{.Status}}
|
||||
策略名称:{{.Sname}}
|
||||
告警设备:{{.Endpoint}}
|
||||
挂载节点:
|
||||
{{range .Bindings}}{{.}}
|
||||
{{end}}监控指标:{{.Metric}}
|
||||
指标标签:{{.Tags}}
|
||||
当前值:{{.Value}}
|
||||
报警说明:{{.Info}}
|
||||
触发时间:{{.Etime}}
|
||||
报警详情:{{.Elink}}
|
||||
报警策略:{{.Slink}}
|
||||
{{if .HasClaim}}认领报警:{{.Clink}}{{end}}
|
|
@ -0,0 +1,34 @@
|
|||
backend:
|
||||
datasource: "tsdb"
|
||||
tsdb:
|
||||
enabled: true
|
||||
name: "tsdb"
|
||||
cluster:
|
||||
tsdb01: 127.0.0.1:5821
|
||||
influxdb:
|
||||
enabled: false
|
||||
username: "influx"
|
||||
password: "admin123"
|
||||
precision: "s"
|
||||
database: "n9e"
|
||||
address: "http://127.0.0.1:8086"
|
||||
opentsdb:
|
||||
enabled: false
|
||||
address: "127.0.0.1:4242"
|
||||
kafka:
|
||||
enabled: false
|
||||
brokersPeers: "192.168.1.1:9092,192.168.1.2:9092"
|
||||
topic: "n9e"
|
||||
aggr:
|
||||
enabled: false
|
||||
kafkaAddrs:
|
||||
- ecmc-01.py:9092
|
||||
- ecmc-02.py:9092
|
||||
- ecmc-03.py:9092
|
||||
kafkaAggrInTopic: aggrin
|
||||
kafkaAggrOutTopic: aggrout
|
||||
|
||||
logger:
|
||||
dir: logs/transfer
|
||||
level: WARNING
|
||||
keepHours: 2
|
|
@ -0,0 +1,54 @@
|
|||
module github.com/didi/nightingale
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/Shopify/sarama v1.19.0
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/codegangsta/negroni v1.0.0
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/dgryski/go-tsz v0.0.0-20180227144327-03b7d791f4fe
|
||||
github.com/eapache/go-resiliency v1.2.0 // indirect
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
|
||||
github.com/eapache/queue v1.1.0 // indirect
|
||||
github.com/garyburd/redigo v1.6.2
|
||||
github.com/gin-contrib/pprof v1.3.0
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/google/go-cmp v0.5.1 // indirect
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/gorilla/context v1.1.1 // indirect
|
||||
github.com/gorilla/mux v1.6.2
|
||||
github.com/hpcloud/tail v1.0.0
|
||||
github.com/influxdata/influxdb v1.8.0
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mattn/go-sqlite3 v1.14.0 // indirect
|
||||
github.com/onsi/ginkgo v1.7.0 // indirect
|
||||
github.com/onsi/gomega v1.4.3 // indirect
|
||||
github.com/open-falcon/rrdlite v0.0.0-20200214140804-bf5829f786ad
|
||||
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
|
||||
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62 // indirect
|
||||
github.com/shirou/gopsutil v2.20.7+incompatible
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/toolkits/pkg v1.1.2
|
||||
github.com/ugorji/go/codec v1.1.7
|
||||
github.com/unrolled/render v1.0.3
|
||||
go.uber.org/automaxprocs v1.3.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/ldap.v3 v3.1.0
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d
|
||||
xorm.io/core v0.7.3
|
||||
xorm.io/xorm v0.8.1
|
||||
)
|
|
@ -0,0 +1,701 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
|
||||
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dgryski/go-tsz v0.0.0-20180227144327-03b7d791f4fe h1:VOrqop9SqFzqwZpROEOZpIufuLEUoJ3reNhdOdC9Zzw=
|
||||
github.com/dgryski/go-tsz v0.0.0-20180227144327-03b7d791f4fe/go.mod h1:ft6P746mYUFQBCsH3OkFBG8FtjLx1XclLMo+9Jh1Yts=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=
|
||||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
|
||||
github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0=
|
||||
github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmcMO9rkaVY=
|
||||
github.com/influxdata/influxdb v1.8.0 h1:/X+G+i3udzHVxpBMuXdPZcUbkIE0ouT+6U+CzQTsOys=
|
||||
github.com/influxdata/influxdb v1.8.0/go.mod h1:SIzcnsjaHRFpmlxpJ4S3NT64qtEKYweNTUMb/vh0OMQ=
|
||||
github.com/influxdata/influxql v1.1.0/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo=
|
||||
github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE=
|
||||
github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8=
|
||||
github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=
|
||||
github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/open-falcon/rrdlite v0.0.0-20200214140804-bf5829f786ad h1:GXUy5t8CYdaaEj1lRnE22CbHVY1M5h6Rv4kk0PJQc54=
|
||||
github.com/open-falcon/rrdlite v0.0.0-20200214140804-bf5829f786ad/go.mod h1:pXROoG0iWVnqq4u2Ii97S0Vt9iCTVypshsl9HXsV6cs=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f h1:JDEmUDtyiLMyMlFwiaDOv2hxUp35497fkwePcLeV7j4=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f/go.mod h1:hoLfEwdY11HjRfKFH6KqnPsfxlo3BP6bJehpDv8t6sQ=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62 h1:pyecQtsPmlkCsMkYhT5iZ+sUXuwee+OvfuJjinEA3ko=
|
||||
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62/go.mod h1:65XQgovT59RWatovFwnwocoUxiI/eENTnOY5GK3STuY=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil v2.20.7+incompatible h1:Ymv4OD12d6zm+2yONe39VSmp2XooJe8za7ngOLW/o/w=
|
||||
github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/toolkits/pkg v1.1.2 h1:BygBwfbL+kiYBH6Rlrx6hKC3WTvNQCsDDOy8keYFNCM=
|
||||
github.com/toolkits/pkg v1.1.2/go.mod h1:ge83E8FQqUnFk+2wtVtZ8kvbmoSjE1l8FP3f+qmR0fY=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/unrolled/render v1.0.3 h1:baO+NG1bZSF2WR4zwh+0bMWauWky7DVrTOfvE2w+aFo=
|
||||
github.com/unrolled/render v1.0.3/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0=
|
||||
go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d h1:QQrM/CCYEzTs91GZylDCQjGHudbPTxF/1fvXdVh5lMo=
|
||||
golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
||||
gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ldap.v3 v3.1.0 h1:DIDWEjI7vQWREh0S8X5/NFPCZ3MCVd55LmXKPW4XLGE=
|
||||
gopkg.in/ldap.v3 v3.1.0/go.mod h1:dQjCc0R0kfyFjIlWNMH1DORwUASZyDxo2Ry1B51dXaQ=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
|
||||
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d h1:7Kns6qqhMAQWvGkxYOLSLRZ5hJO0/5pcE5lPGP2fxUw=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d/go.mod h1:3jediapYqJ2w1BFw7lAZPCx7scubsTfosqHkhXCWJKw=
|
||||
k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc=
|
||||
k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
|
||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
||||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
||||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0=
|
||||
xorm.io/core v0.7.3/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
xorm.io/xorm v0.8.1 h1:4f2KXuQxVdaX3RdI3Fw81NzMiSpZeyCZt8m3sEVeIkQ=
|
||||
xorm.io/xorm v0.8.1/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
|
|
@ -0,0 +1,30 @@
|
|||
set names utf8;
|
||||
|
||||
drop database if exists n9e_ams;
|
||||
create database n9e_ams;
|
||||
use n9e_ams;
|
||||
|
||||
CREATE TABLE `host`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`sn` char(128) not null default '',
|
||||
`ip` char(15) not null,
|
||||
`ident` varchar(128) not null default '',
|
||||
`name` varchar(128) not null default '',
|
||||
`cpu` varchar(255) not null default '',
|
||||
`mem` varchar(255) not null default '',
|
||||
`disk` varchar(255) not null default '',
|
||||
`note` varchar(255) not null default 'different with resource note',
|
||||
`cate` varchar(32) not null comment 'host,vm,container,switch',
|
||||
`tenant` varchar(128) not null default '',
|
||||
`clock` bigint not null comment 'heartbeat timestamp',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`ip`),
|
||||
UNIQUE KEY (`ident`),
|
||||
KEY (`sn`),
|
||||
KEY (`name`),
|
||||
KEY (`tenant`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
/* 网络设备管理、机柜机架、配件耗材等相关的功能是商业版本才有的,表结构不要放到这里 */
|
|
@ -0,0 +1,29 @@
|
|||
set names utf8;
|
||||
|
||||
drop database if exists n9e_hbs;
|
||||
create database n9e_hbs;
|
||||
use n9e_hbs;
|
||||
|
||||
create table `instance` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`module` varchar(32) not null,
|
||||
`identity` varchar(255) not null,
|
||||
`rpc_port` varchar(16) not null,
|
||||
`http_port` varchar(16) not null,
|
||||
`remark` text,
|
||||
`ts` int unsigned not null,
|
||||
primary key (`id`),
|
||||
key(`module`,`identity`,`rpc_port`,`http_port`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `detector` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`module` varchar(32) not null,
|
||||
`node` varchar(16) not null,
|
||||
`region` varchar(64) not null,
|
||||
`ip` varchar(255) not null,
|
||||
`port` varchar(16) not null,
|
||||
`ts` int unsigned not null,
|
||||
primary key (`id`),
|
||||
key(`ip`,`port`)
|
||||
) engine=innodb default charset=utf8;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,400 @@
|
|||
set names utf8;
|
||||
|
||||
drop database if exists n9e_mon;
|
||||
create database n9e_mon;
|
||||
use n9e_mon;
|
||||
|
||||
create table `maskconf` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`nid` int unsigned not null,
|
||||
`category` int(1) NOT NULL COMMENT '1 机器 2业务',
|
||||
`metric` varchar(255) not null,
|
||||
`tags` varchar(255) not null default '',
|
||||
`cause` varchar(255) not null default '',
|
||||
`user` varchar(32) not null default 'operate user',
|
||||
`btime` bigint not null default 0 comment 'begin time',
|
||||
`etime` bigint not null default 0 comment 'end time',
|
||||
primary key (`id`),
|
||||
key(`nid`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `maskconf_endpoints` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`mask_id` int unsigned not null,
|
||||
`endpoint` varchar(255) not null,
|
||||
primary key (`id`),
|
||||
key(`mask_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `maskconf_nids` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`mask_id` int unsigned not null,
|
||||
`nid` varchar(255) not null,
|
||||
`path` varchar(255) not null,
|
||||
primary key (`id`),
|
||||
key(`mask_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `screen` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`node_id` int unsigned not null comment 'service tree node id',
|
||||
`name` varchar(255) not null,
|
||||
`last_updator` varchar(64) not null default '',
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
primary key (`id`),
|
||||
key(`node_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `screen_subclass` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`screen_id` int unsigned not null,
|
||||
`name` varchar(255) not null,
|
||||
`weight` int not null default 0,
|
||||
primary key (`id`),
|
||||
key(`screen_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `chart` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`subclass_id` int unsigned not null,
|
||||
`configs` varchar(8192),
|
||||
`weight` int not null default 0,
|
||||
primary key (`id`),
|
||||
key(`subclass_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `tmp_chart` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`configs` varchar(8192),
|
||||
`creator` varchar(64) not null,
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
primary key (`id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `event_cur` (
|
||||
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
||||
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
||||
`sname` varchar(255) not null default '' comment 'name, 报警通知名称',
|
||||
`node_path` varchar(255) not null default '' comment 'node path',
|
||||
`nid` int unsigned not null default '0' comment 'node id',
|
||||
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
||||
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
||||
`cur_node_path` varchar(255) not null default '' comment 'cur_node_path',
|
||||
`cur_nid` varchar(45) not null default '' comment 'cur_nid',
|
||||
`priority` tinyint(4) not null default 2 comment '优先级',
|
||||
`event_type` varchar(45) not null default '' comment 'alert|recovery',
|
||||
`category` tinyint(4) not null default 2 comment '1阈值 2智能',
|
||||
`status` int(10) not null default 0 comment 'event status',
|
||||
`detail` text comment 'counter points pred_points 详情',
|
||||
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
||||
`etime` bigint(20) not null default 0 comment 'event ts',
|
||||
`value` varchar(255) not null default '' comment '当前值',
|
||||
`users` varchar(512) not null default '[]' comment 'notify users',
|
||||
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
||||
`runbook` varchar(1024) NOT NULL DEFAULT '' COMMENT 'runbook url',
|
||||
`info` varchar(512) not null default '' comment 'strategy info',
|
||||
`ignore_alert` int(2) not null default 0 comment 'ignore event',
|
||||
`claimants` varchar(512) not null default '[]' comment 'claimants',
|
||||
`need_upgrade` int(2) not null default 0 comment 'need upgrade',
|
||||
`alert_upgrade` text comment 'alert upgrade',
|
||||
`created` DATETIME not null default '1971-1-1 00:00:00' comment 'created',
|
||||
KEY `idx_id` (`id`),
|
||||
KEY `idx_sid` (`sid`),
|
||||
KEY `idx_hashid` (`hashid`),
|
||||
KEY `idx_node_path` (`node_path`),
|
||||
KEY `idx_etime` (`etime`)
|
||||
) engine=innodb default charset=utf8 comment 'event';
|
||||
|
||||
create table `event` (
|
||||
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
||||
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
||||
`sname` varchar(255) not null default '' comment 'name, 报警通知名称',
|
||||
`node_path` varchar(255) not null default '' comment 'node path',
|
||||
`nid` int unsigned not null default '0' comment 'node id',
|
||||
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
||||
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
||||
`cur_node_path` varchar(255) not null default '' comment 'cur_node_path',
|
||||
`cur_nid` varchar(45) not null default '' comment 'cur_nid',
|
||||
`priority` tinyint(4) not null default 2 comment '优先级',
|
||||
`event_type` varchar(45) not null default '' comment 'alert|recovery',
|
||||
`category` tinyint(4) not null default 2 comment '1阈值 2智能',
|
||||
`status` int(10) not null default 0 comment 'event status',
|
||||
`detail` text comment 'counter points pred_points 详情',
|
||||
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
||||
`etime` bigint(20) not null default 0 comment 'event ts',
|
||||
`value` varchar(255) not null default '' comment '当前值',
|
||||
`users` varchar(512) not null default '[]' comment 'notify users',
|
||||
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
||||
`runbook` varchar(1024) NOT NULL DEFAULT '' COMMENT 'runbook url',
|
||||
`info` varchar(512) not null default '' comment 'strategy info',
|
||||
`need_upgrade` int(2) not null default 0 comment 'need upgrade',
|
||||
`alert_upgrade` text not null comment 'alert upgrade',
|
||||
`created` DATETIME not null default '1971-1-1 00:00:00' comment 'created',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_id` (`id`),
|
||||
KEY `idx_sid` (`sid`),
|
||||
KEY `idx_hashid` (`hashid`),
|
||||
KEY `idx_node_path` (`node_path`),
|
||||
KEY `idx_etime` (`etime`),
|
||||
KEY `idx_event_type` (`event_type`),
|
||||
KEY `idx_status` (`status`)
|
||||
) engine=innodb default charset=utf8 comment 'event';
|
||||
|
||||
CREATE TABLE `stra` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL COMMENT 'strategy name',
|
||||
`category` int(1) NOT NULL COMMENT '1 机器 2业务',
|
||||
`nid` int(10) NOT NULL COMMENT '服务树节点id',
|
||||
`excl_nid` varchar(255) NOT NULL COMMENT '被排除的服务树叶子节点id',
|
||||
`alert_dur` int(4) NOT NULL COMMENT '单位秒,持续异常n秒则产生异常event',
|
||||
`recovery_dur` int(4) NOT NULL DEFAULT 0 COMMENT '单位秒,持续正常n秒则产生恢复event,0表示立即产生恢复event',
|
||||
`exprs` varchar(1024) NOT NULL DEFAULT '' COMMENT '规则表达式',
|
||||
`tags` varchar(1024) DEFAULT '' COMMENT 'tags过滤',
|
||||
`enable_stime` char(5) NOT NULL DEFAULT '00:00' COMMENT '策略生效开始时间',
|
||||
`enable_etime` char(5) NOT NULL DEFAULT '23:59' COMMENT '策略生效终止时间',
|
||||
`enable_days_of_week` varchar(1024) NOT NULL DEFAULT '[0,1,2,3,4,5,6]' COMMENT '策略生效日期',
|
||||
`converge` varchar(45) NOT NULL DEFAULT '' COMMENT 'n秒最多报m次警',
|
||||
`recovery_notify` int(1) NOT NULL DEFAULT 1 COMMENT '1 发送恢复通知 0不发送恢复通知',
|
||||
`priority` int(1) NOT NULL DEFAULT 3 COMMENT '告警等级',
|
||||
`notify_group` varchar(255) NOT NULL DEFAULT '' COMMENT '告警通知组',
|
||||
`notify_user` varchar(255) NOT NULL DEFAULT '' COMMENT '告警通知人',
|
||||
`callback` varchar(1024) NOT NULL DEFAULT '' COMMENT 'callback url',
|
||||
`runbook` varchar(1024) NOT NULL DEFAULT '' COMMENT 'runbook url',
|
||||
`work_groups` varchar(255) NOT NULL DEFAULT '' COMMENT 'work_groups',
|
||||
`creator` varchar(64) NOT NULL COMMENT '创建者',
|
||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
`last_updator` varchar(64) NOT NULL DEFAULT '',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`need_upgrade` int(2) not null default 0 comment 'need upgrade',
|
||||
`alert_upgrade` text comment 'alert upgrade',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `stra_log` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`sid` bigint(20) NOT NULL DEFAULT '0' COMMENT 'collect id',
|
||||
`action` varchar(255) NOT NULL DEFAULT '' COMMENT '动作 update, delete',
|
||||
`body` text COMMENT '修改之前采集的内容',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_sid` (`sid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `port_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'PORT' COMMENT 'type',
|
||||
`nid` int(10) NOT NULL COMMENT '服务树节点id',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`tags` varchar(255) NOT NULL DEFAULT '' COMMENT 'tags',
|
||||
`port` int(11) NOT NULL DEFAULT '0' COMMENT 'port',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`timeout` int(11) NOT NULL DEFAULT '0' COMMENT 'connect time',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(128) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last_updated',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'port collect';
|
||||
|
||||
CREATE TABLE `proc_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`tags` varchar(255) NOT NULL DEFAULT '' COMMENT 'tags',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'PROC' COMMENT 'type',
|
||||
`collect_method` varchar(64) NOT NULL DEFAULT 'name' COMMENT '采集方式',
|
||||
`target` varchar(255) NOT NULL DEFAULT '' COMMENT '采集对象',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(128) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'proc collect';
|
||||
|
||||
CREATE TABLE `log_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`tags` varchar(2048) NOT NULL DEFAULT '' COMMENT 'tags',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'LOG' COMMENT 'type',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`file_path` varchar(255) NOT NULL DEFAULT '' COMMENT 'file path',
|
||||
`time_format` varchar(128) NOT NULL DEFAULT '' COMMENT 'time format',
|
||||
`pattern` varchar(1024) NOT NULL DEFAULT '' COMMENT 'pattern',
|
||||
`func` varchar(64) NOT NULL DEFAULT '' COMMENT 'func',
|
||||
`degree` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'degree',
|
||||
`func_type` varchar(64) NOT NULL DEFAULT '' COMMENT 'func_type',
|
||||
`aggregate` varchar(64) NOT NULL DEFAULT '' COMMENT 'aggr',
|
||||
`unit` varchar(64) NOT NULL DEFAULT '' COMMENT 'unit',
|
||||
`zero_fill` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'zero fill',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(128) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'log collect';
|
||||
|
||||
CREATE TABLE `plugin_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'PROC' COMMENT 'type',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`file_path` varchar(255) NOT NULL COMMENT 'file_path',
|
||||
`params` varchar(255) NOT NULL COMMENT 'params',
|
||||
`stdin` text NOT NULL COMMENT 'stdin',
|
||||
`env` text NOT NULL COMMENT 'env',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(128) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'plugin collect';
|
||||
|
||||
CREATE TABLE `api_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`domain` varchar(255) NOT NULL DEFAULT '' COMMENT 'domain',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'API' COMMENT 'type',
|
||||
`path` varchar(255) NOT NULL DEFAULT '/' COMMENT 'path&querystring',
|
||||
`header` varchar(1024) NOT NULL DEFAULT '' COMMENT 'headers',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT 'step',
|
||||
`timeout` int(11) NOT NULL DEFAULT '0' COMMENT 'total timeout',
|
||||
`protocol` varchar(20) NOT NULL DEFAULT 'http' COMMENT 'protocol',
|
||||
`port` varchar(20) NOT NULL DEFAULT '0' COMMENT 'port',
|
||||
`method` varchar(10) NOT NULL DEFAULT 'get' COMMENT 'method',
|
||||
`max_redirect` smallint(2) NOT NULL DEFAULT '0' COMMENT 'max_redirect',
|
||||
`post_body` text COMMENT 'post_body',
|
||||
`expected_code` varchar(255) NOT NULL DEFAULT '[]' COMMENT 'expected_code',
|
||||
`expected_string` varchar(255) NOT NULL DEFAULT '' COMMENT 'expected_string',
|
||||
`unexpected_string` varchar(255) NOT NULL DEFAULT '' COMMENT 'unexpected_string',
|
||||
`region` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'region',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(128) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'api collect';
|
||||
|
||||
CREATE TABLE `snmp_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'SNMP' COMMENT 'collect_type',
|
||||
`oid_type` int(1) NOT NULL DEFAULT 1 COMMENT 'oid_type',
|
||||
`module` varchar(255) NOT NULL DEFAULT '' COMMENT 'module',
|
||||
`metric` varchar(255) NOT NULL DEFAULT '' COMMENT 'metric',
|
||||
`metric_type` varchar(255) NOT NULL DEFAULT '' COMMENT 'metric_type',
|
||||
`oid` varchar(255) NOT NULL DEFAULT '' COMMENT 'oid',
|
||||
`indexes` text NOT NULL COMMENT 'indexes',
|
||||
`port` int(5) NOT NULL DEFAULT 161 COMMENT 'port',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT 'step',
|
||||
`timeout` int(11) NOT NULL DEFAULT '0' COMMENT 'total timeout',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(128) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_module` (`module`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'api collect';
|
||||
|
||||
CREATE TABLE `aggr_calc` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`category` int(1) NOT NULL COMMENT '1 机器 2业务',
|
||||
`new_metric` varchar(255) NOT NULL DEFAULT '' COMMENT 'new_metric',
|
||||
`new_step` int(11) NOT NULL DEFAULT '0' COMMENT 'new_step',
|
||||
`groupby` varchar(255) NOT NULL DEFAULT '' COMMENT 'groupby',
|
||||
`raw_metrics` text comment 'raw_metrics',
|
||||
`global_operator` varchar(32) NOT NULL DEFAULT '' COMMENT 'global_operator',
|
||||
`expression` varchar(255) NOT NULL DEFAULT '' COMMENT 'expression',
|
||||
`rpn` varchar(255) NOT NULL DEFAULT '' COMMENT 'rpn',
|
||||
`status` int(1) NOT NULL COMMENT '',
|
||||
`quota` int(10) NOT NULL COMMENT '',
|
||||
`comment` varchar(255) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(64) NOT NULL COMMENT '创建者',
|
||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
`last_updator` varchar(64) NOT NULL DEFAULT '',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_new_metric` (`new_metric`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'aggr_calc';
|
||||
|
||||
CREATE TABLE `nginx_log_stra` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`service` varchar(255) NOT NULL DEFAULT '' COMMENT 'service',
|
||||
`interval` int(11) NOT NULL DEFAULT '0' COMMENT 'interval',
|
||||
`domain` varchar(2048) NOT NULL DEFAULT '' COMMENT 'domain',
|
||||
`url_path_prefix` varchar(2048) NOT NULL DEFAULT '' COMMENT 'url_path_prefix',
|
||||
`append_tags` varchar(2048) NOT NULL DEFAULT '' COMMENT 'append_tags',
|
||||
`creator` varchar(64) NOT NULL COMMENT '创建者',
|
||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
`last_updator` varchar(64) NOT NULL DEFAULT '',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'nginx_log_stra';
|
||||
|
||||
CREATE TABLE `binlog_stra` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`metric` varchar(255) NOT NULL DEFAULT '' COMMENT 'metric',
|
||||
`interval` int(11) NOT NULL DEFAULT '0' COMMENT 'interval',
|
||||
`db` varchar(2048) NOT NULL DEFAULT '' COMMENT 'db',
|
||||
`column_change` varchar(2048) NOT NULL DEFAULT '' COMMENT 'column_change',
|
||||
`tags_column` varchar(2048) NOT NULL DEFAULT '' COMMENT 'tags_column',
|
||||
`append_tags` varchar(2048) NOT NULL DEFAULT '' COMMENT 'append_tags',
|
||||
`func` varchar(255) NOT NULL DEFAULT '' COMMENT 'func',
|
||||
`sql_type` varchar(255) NOT NULL DEFAULT '' COMMENT 'sql_type',
|
||||
`value_column` varchar(255) NOT NULL DEFAULT '' COMMENT 'value_column',
|
||||
`creator` varchar(64) NOT NULL COMMENT '创建者',
|
||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
`last_updator` varchar(64) NOT NULL DEFAULT '',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'binlog_stra';
|
||||
|
||||
CREATE TABLE `collect_hist` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'collect id',
|
||||
`collect_type` varchar(255) NOT NULL DEFAULT '' COMMENT '采集的种类 log,port,proc,api',
|
||||
`action` varchar(8) NOT NULL DEFAULT '' COMMENT '动作 update, delete',
|
||||
`body` text COMMENT '修改之前采集的内容',
|
||||
`creator` varchar(128) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_cid` (`cid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'hist';
|
||||
|
||||
|
||||
CREATE TABLE `api_collect_sid` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`sid` bigint(20) NOT NULL DEFAULT '0' COMMENT 'stra id',
|
||||
`cid` bigint(20) NOT NULL DEFAULT '0' COMMENT 'collect id',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`sid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
@ -0,0 +1,286 @@
|
|||
set names utf8;
|
||||
|
||||
drop database if exists n9e_rdb;
|
||||
create database n9e_rdb;
|
||||
use n9e_rdb;
|
||||
|
||||
CREATE TABLE `user`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`uuid` varchar(128) not null comment 'use in cookie',
|
||||
`username` varchar(64) not null comment 'login name, cannot rename',
|
||||
`password` varchar(128) not null default '',
|
||||
`dispname` varchar(32) not null default '' comment 'display name, chinese name',
|
||||
`phone` varchar(16) not null default '',
|
||||
`email` varchar(64) not null default '',
|
||||
`im` varchar(64) not null default '',
|
||||
`portrait` varchar(2048) not null default '',
|
||||
`intro` text not null default '',
|
||||
`is_root` tinyint(1) not null,
|
||||
`leader_id` int unsigned not null default 0,
|
||||
`leader_name` varchar(32) not null default '',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`username`),
|
||||
UNIQUE KEY (`uuid`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `user_token`
|
||||
(
|
||||
`user_id` int unsigned not null,
|
||||
`username` varchar(128) not null,
|
||||
`token` varchar(128) not null,
|
||||
KEY (`user_id`),
|
||||
KEY (`username`),
|
||||
UNIQUE KEY (`token`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `invite`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`token` varchar(128) not null,
|
||||
`expire` bigint not null,
|
||||
`creator` varchar(32) not null,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`token`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `team`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`ident` varchar(255) not null,
|
||||
`name` varchar(255) not null default '',
|
||||
`note` varchar(255) not null default '',
|
||||
`mgmt` int(1) not null comment '0: member manage; 1: admin manage',
|
||||
`creator` int unsigned not null,
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`ident`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `team_user`
|
||||
(
|
||||
`team_id` int unsigned not null,
|
||||
`user_id` int unsigned not null,
|
||||
`is_admin` tinyint(1) not null,
|
||||
KEY (`team_id`),
|
||||
KEY (`user_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `configs`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`ckey` varchar(255) not null,
|
||||
`cval` varchar(255) not null default '',
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`ckey`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `node_cate`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`ident` char(128) not null default '' comment 'cluster,service,module,department,product...',
|
||||
`name` varchar(255) not null default '',
|
||||
`icon_color` char(7) not null default '' comment 'e.g. #108AC6',
|
||||
`protected` tinyint(1) not null default 0 comment 'if =1, cannot delete',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`ident`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
insert into node_cate(ident, name, icon_color, protected)
|
||||
values ('tenant', '租户', '#de83cb', 1);
|
||||
insert into node_cate(ident, name, icon_color, protected)
|
||||
values ('organization', '组织', '#ff8e75', 1);
|
||||
insert into node_cate(ident, name, icon_color, protected)
|
||||
values ('project', '项目', '#f6bb4a', 1);
|
||||
insert into node_cate(ident, name, icon_color, protected)
|
||||
values ('module', '模块', '#6dc448', 1);
|
||||
insert into node_cate(ident, name, icon_color, protected)
|
||||
values ('cluster', '集群', '#94c7c6', 1);
|
||||
insert into node_cate(ident, name, icon_color, protected)
|
||||
values ('resource', '资源', '#a7aae6', 1);
|
||||
|
||||
CREATE TABLE `node_cate_field`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`cate` char(32) not null default '' comment 'cluster,service,module,department,product...',
|
||||
`field_ident` varchar(255) not null comment 'english identity',
|
||||
`field_name` varchar(255) not null comment 'chinese name',
|
||||
`field_type` varchar(64) not null,
|
||||
`field_required` tinyint(1) not null default 0,
|
||||
`field_extra` varchar(2048) not null default '',
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`cate`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `node_field_value`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`node_id` int unsigned not null,
|
||||
`field_ident` varchar(255) not null,
|
||||
`field_value` varchar(1024) not null default '',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`node_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `node`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`pid` int unsigned not null,
|
||||
`ident` varchar(128) not null,
|
||||
`name` varchar(255) not null default '',
|
||||
`note` varchar(255) not null default '',
|
||||
`path` varchar(255) not null comment 'ident1.ident2.ident3',
|
||||
`leaf` tinyint(1) not null,
|
||||
`cate` char(128) not null default '' comment 'cluster,service,module,department,product...',
|
||||
`icon_color` char(7) not null default '' comment 'e.g. #108AC6',
|
||||
`icon_char` char(1) not null default '' comment 'cluster->C,service->S,module->M',
|
||||
`proxy` tinyint(1) not null default 0 comment '0:myself management, 1:other module management',
|
||||
`creator` varchar(64) not null,
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`path`),
|
||||
KEY (`cate`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
insert into node(id, ident, name, note, pid, path, leaf, cate, icon_color, icon_char, proxy, creator)
|
||||
values (1, 'inner', '内置租户', '用于平台管理视角的资源监控', 0, 'inner', 0, 'tenant', '#de83cb', 'T', 0, 'root');
|
||||
|
||||
CREATE TABLE `node_trash`
|
||||
(
|
||||
`id` int unsigned not null,
|
||||
`pid` int unsigned not null,
|
||||
`ident` varchar(128) not null,
|
||||
`name` varchar(255) not null default '',
|
||||
`note` varchar(255) not null default '',
|
||||
`path` varchar(255) not null comment 'ident1.ident2.ident3',
|
||||
`leaf` tinyint(1) not null,
|
||||
`cate` char(128) not null default '' comment 'cluster,service,module,department,product...',
|
||||
`icon_color` char(7) not null default '' comment 'e.g. #108AC6',
|
||||
`icon_char` char(1) not null default '' comment 'cluster->C,service->S,module->M',
|
||||
`proxy` tinyint(1) not null default 0 comment '0:myself management, 1:other module management',
|
||||
`creator` varchar(64) not null,
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`path`),
|
||||
KEY (`cate`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `node_admin`
|
||||
(
|
||||
`node_id` int unsigned not null,
|
||||
`user_id` int unsigned not null,
|
||||
KEY (`node_id`),
|
||||
KEY (`user_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `resource`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`uuid` varchar(255) not null,
|
||||
`ident` varchar(255) not null,
|
||||
`name` varchar(255) not null default '',
|
||||
`labels` varchar(255) not null default '' comment 'e.g. flavor=2c4g300g,region=bj,os=windows',
|
||||
`note` varchar(255) not null default '',
|
||||
`extend` varchar(1024) not null default '' comment 'json',
|
||||
`cate` varchar(64) not null comment 'host,vm,container,switch,redis,mongo',
|
||||
`tenant` varchar(128) not null default '',
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`uuid`),
|
||||
UNIQUE KEY (`ident`),
|
||||
KEY (`tenant`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `node_resource`
|
||||
(
|
||||
`node_id` int unsigned not null,
|
||||
`res_id` int unsigned not null,
|
||||
KEY (`node_id`),
|
||||
KEY (`res_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `node_role`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`node_id` int unsigned not null,
|
||||
`username` varchar(64) not null,
|
||||
`role_id` int unsigned not null,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`node_id`),
|
||||
KEY (`role_id`),
|
||||
KEY (`username`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `role`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`name` varchar(128) not null default '',
|
||||
`note` varchar(255) not null default '',
|
||||
`cate` char(6) not null default '' comment 'category: global or local',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`name`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `role_operation`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`role_id` int unsigned not null,
|
||||
`operation` varchar(255) not null,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`role_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `role_global_user`
|
||||
(
|
||||
`role_id` int unsigned not null,
|
||||
`user_id` int unsigned not null,
|
||||
KEY (`role_id`),
|
||||
KEY (`user_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `login_log`
|
||||
(
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`username` varchar(64) not null,
|
||||
`client` varchar(128) not null comment 'client ip',
|
||||
`clock` bigint not null comment 'login timestamp',
|
||||
`loginout` char(3) not null comment 'in or out',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`username`),
|
||||
KEY (`clock`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE `operation_log`
|
||||
(
|
||||
`id` bigint unsigned not null AUTO_INCREMENT,
|
||||
`username` varchar(64) not null,
|
||||
`clock` bigint not null comment 'operation timestamp',
|
||||
`res_cl` char(16) not null default '' comment 'resource class',
|
||||
`res_id` varchar(128) not null default '',
|
||||
`detail` varchar(512) not null,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`clock`),
|
||||
KEY (`res_cl`, `res_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8;
|
|
@ -0,0 +1,137 @@
|
|||
package address
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/toolkits/pkg/file"
|
||||
"github.com/toolkits/pkg/runner"
|
||||
)
|
||||
|
||||
type Module struct {
|
||||
HTTP string `yaml:"http"`
|
||||
RPC string `yaml:"rpc"`
|
||||
Addresses []string `yaml:"addresses"`
|
||||
}
|
||||
|
||||
var (
|
||||
lock sync.Once
|
||||
mods map[string]Module
|
||||
)
|
||||
|
||||
func GetHTTPListen(mod string) string {
|
||||
return getMod(mod).HTTP
|
||||
}
|
||||
|
||||
func GetHTTPPort(mod string) int {
|
||||
return convPort(mod, getMod(mod).HTTP, "http")
|
||||
}
|
||||
|
||||
func GetRPCListen(mod string) string {
|
||||
return getMod(mod).RPC
|
||||
}
|
||||
|
||||
func GetRPCPort(mod string) int {
|
||||
return convPort(mod, getMod(mod).RPC, "rpc")
|
||||
}
|
||||
|
||||
func convPort(module, listen, portType string) int {
|
||||
splitChar := ":"
|
||||
if IsIPv6(listen) {
|
||||
splitChar = "]:"
|
||||
}
|
||||
port, err := strconv.Atoi(strings.Split(listen, splitChar)[1])
|
||||
if err != nil {
|
||||
fmt.Printf("%s.%s invalid", module, portType)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return port
|
||||
}
|
||||
|
||||
func GetHTTPAddresses(mod string) []string {
|
||||
modConf := getMod(mod)
|
||||
|
||||
count := len(modConf.Addresses)
|
||||
if count == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
port := convPort(mod, modConf.HTTP, "http")
|
||||
|
||||
addresses := make([]string, count)
|
||||
for i := 0; i < count; i++ {
|
||||
addresses[i] = fmt.Sprintf("%s:%d", modConf.Addresses[i], port)
|
||||
}
|
||||
|
||||
return addresses
|
||||
}
|
||||
|
||||
func GetRPCAddresses(mod string) []string {
|
||||
modConf := getMod(mod)
|
||||
|
||||
count := len(modConf.Addresses)
|
||||
if count == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
port := convPort(mod, modConf.RPC, "rpc")
|
||||
|
||||
addresses := make([]string, count)
|
||||
for i := 0; i < count; i++ {
|
||||
addresses[i] = fmt.Sprintf("%s:%d", modConf.Addresses[i], port)
|
||||
}
|
||||
|
||||
return addresses
|
||||
}
|
||||
|
||||
func getMod(modKey string) Module {
|
||||
lock.Do(func() {
|
||||
parseConf()
|
||||
})
|
||||
|
||||
mod, has := mods[modKey]
|
||||
if !has {
|
||||
fmt.Printf("module(%s) configuration section not found", modKey)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return mod
|
||||
}
|
||||
|
||||
func parseConf() {
|
||||
conf := getConf()
|
||||
|
||||
var c map[string]Module
|
||||
err := file.ReadYaml(conf, &c)
|
||||
if err != nil {
|
||||
fmt.Println("cannot parse file:", conf)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
mods = c
|
||||
}
|
||||
|
||||
func getConf() string {
|
||||
conf := path.Join(runner.Cwd, "etc", "address.local.yml")
|
||||
if file.IsExist(conf) {
|
||||
return conf
|
||||
}
|
||||
|
||||
conf = path.Join(runner.Cwd, "etc", "address.yml")
|
||||
if file.IsExist(conf) {
|
||||
return conf
|
||||
}
|
||||
|
||||
fmt.Println("configuration file address.[local.]yml not found")
|
||||
os.Exit(1)
|
||||
return ""
|
||||
}
|
||||
|
||||
func IsIPv6(address string) bool {
|
||||
return strings.Count(address, ":") >= 2
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type AggrCalc struct {
|
||||
Id int64 `xorm:"id pk autoincr" json:"id"`
|
||||
Nid int64 `xorm:"nid" json:"nid"`
|
||||
Category int `xorm:"category" json:"category"`
|
||||
NewMetric string `xorm:"new_metric" json:"new_metric"`
|
||||
NewStep int `xorm:"new_step" json:"new_step"`
|
||||
GroupByString string `xorm:"groupby" json:"-"`
|
||||
RawMetricsString string `xorm:"raw_metrics" json:"-"`
|
||||
GlobalOperator string `xorm:"global_operator"json:"global_operator"` //指标聚合方式
|
||||
Expression string `xorm:"expression" json:"expression"`
|
||||
RPN string `xorm:"rpn" json:"rpn"`
|
||||
Status int `xorm:"status" json:"-"`
|
||||
Quota int `xorm:"quota" json:"quota"`
|
||||
Comment string `xorm:"comment" json:"comment"`
|
||||
Creator string `xorm:"creator" json:"creator"`
|
||||
Created time.Time `xorm:"created" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"<-" json:"last_updated"`
|
||||
|
||||
RawMetrics []*RawMetric `xorm:"-" json:"raw_metrics"`
|
||||
GroupBy []string `xorm:"-" json:"groupby"`
|
||||
}
|
||||
|
||||
type RawMetric struct {
|
||||
Nid int64 `json:"nid"`
|
||||
ExclNid []int64 `json:"excl_nid"`
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Nids []string `json:"nids"`
|
||||
VarID string `json:"var_id"`
|
||||
Name string `json:"name"`
|
||||
Opt string `json:"opt"`
|
||||
Filters []*AggrTagsFilter `json:"filters"`
|
||||
}
|
||||
|
||||
type AggrTagsFilter struct {
|
||||
TagK string `json:"tagk"`
|
||||
Opt string `json:"opt"`
|
||||
TagV []string `json:"tagv"`
|
||||
}
|
||||
|
||||
type RawMetricAggrCalc struct {
|
||||
Sid int64 `json:"sid"`
|
||||
Nid int64 `json:"nid"`
|
||||
NewMetric string `json:"newMetric"`
|
||||
NewStep int `json:"newStep"`
|
||||
GroupBy []string `json:"groupBy"`
|
||||
GlobalOperator string `json:"globalOperator"`
|
||||
InnerOperator string `json:"innerOperator"`
|
||||
VarID string `json:"varID"`
|
||||
VarNum int `json:"varNum"`
|
||||
SourceNid int64 `json:"source_nid"`
|
||||
SourceMetric string `json:"sourceMetric"`
|
||||
RPN string `json:"RPN"`
|
||||
TagFilters []*AggrTagsFilter `json:"tagFilters"`
|
||||
Lateness int `json:"lateness"`
|
||||
}
|
||||
|
||||
type AggrList struct {
|
||||
Data []*CentralAggrV2Point `json:"data"`
|
||||
}
|
||||
|
||||
type CentralAggrV2Point struct {
|
||||
Timestamp int64 `json:"t"`
|
||||
Value float64 `json:"v"`
|
||||
Strategys []*AggrCalcStra `json:"s"`
|
||||
Hash uint64 `json:"h"`
|
||||
}
|
||||
|
||||
type AggrCalcStra struct {
|
||||
SID int64 `json:"sid"`
|
||||
NID string `json:"nid"`
|
||||
ResultStep int `json:"step"`
|
||||
RawStep int `json:"rawStep"`
|
||||
GroupKey string `json:"key"`
|
||||
GlobalOperator string `json:"global"`
|
||||
InnerOperator string `json:"inner"`
|
||||
VarID string `json:"varID"`
|
||||
VarNum int `json:"varNum"`
|
||||
RPN string `json:"RPN"`
|
||||
Lateness int `json:"lateness"`
|
||||
}
|
||||
|
||||
type AggrOut struct {
|
||||
Index string `json:"index"`
|
||||
Operate int `json:"operate"`
|
||||
Data struct {
|
||||
Nid string `json:"nid"`
|
||||
Step int64 `json:"step"`
|
||||
GroupTag string `json:"groupTag"`
|
||||
Value interface{} `json:"value"`
|
||||
Sid int64 `json:"sid"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
} `json:"data"`
|
||||
Type string `json:"type"`
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package dataobj
|
||||
|
||||
// Event 传递到alarm的结构体, 尽可能少的字段, 发出通知需要的信息由alarm自己补全
|
||||
type Event struct {
|
||||
ID string `json:"-"`
|
||||
Sid int64 `json:"sid"`
|
||||
EventType string `json:"event_type"` // alert/recover
|
||||
Hashid uint64 `json:"hashid"` // 全局唯一 根据counter计算
|
||||
Etime int64 `json:"etime"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
History []History `json:"-"`
|
||||
Detail string `json:"detail"`
|
||||
Info string `json:"info"`
|
||||
Value string `json:"value"`
|
||||
Partition string `json:"-"`
|
||||
CurNid string `json:"cur_nid"`
|
||||
}
|
||||
|
||||
type History struct {
|
||||
Key string `json:"-"` // 用于计算event的hashid
|
||||
Metric string `json:"metric"` // 指标名
|
||||
Tags map[string]string `json:"tags,omitempty"` // endpoint/counter
|
||||
Granularity int `json:"-"` // alarm补齐数据时需要
|
||||
Points []*HistoryData `json:"points"` // 现场值
|
||||
}
|
||||
|
||||
type HistoryData struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Value JsonFloat `json:"value"`
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
func RRDData2HistoryData(datas []*RRDData) []*HistoryData {
|
||||
historyDatas := make([]*HistoryData, len(datas))
|
||||
|
||||
for i := range datas {
|
||||
historyData := &HistoryData{
|
||||
Timestamp: datas[i].Timestamp,
|
||||
Value: datas[i].Value,
|
||||
}
|
||||
historyDatas[i] = historyData
|
||||
}
|
||||
return historyDatas
|
||||
}
|
||||
|
||||
func HistoryData2RRDData(datas []*HistoryData) []*RRDData {
|
||||
rrdDatas := make([]*RRDData, len(datas))
|
||||
|
||||
for i := range datas {
|
||||
data := &RRDData{
|
||||
Timestamp: datas[i].Timestamp,
|
||||
Value: datas[i].Value,
|
||||
}
|
||||
rrdDatas[i] = data
|
||||
}
|
||||
return rrdDatas
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package dataobj
|
||||
|
||||
type IndexModel struct {
|
||||
Nid string `json:"nid"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Metric string `json:"metric"`
|
||||
DsType string `json:"dsType"`
|
||||
Step int `json:"step"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Timestamp int64 `json:"ts"`
|
||||
}
|
||||
|
||||
type IndexResp struct {
|
||||
Msg string
|
||||
Total int
|
||||
Invalid int
|
||||
Latency int64
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package dataobj
|
||||
|
||||
type InfluxdbItem struct {
|
||||
Measurement string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Fields map[string]interface{} `json:"fields"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package dataobj
|
||||
|
||||
type TaskMetaResponse struct {
|
||||
Message string
|
||||
Script string
|
||||
Args string
|
||||
Account string
|
||||
}
|
||||
|
||||
type ReportTask struct {
|
||||
Id int64
|
||||
Clock int64
|
||||
Status string
|
||||
Stdout string
|
||||
Stderr string
|
||||
}
|
||||
|
||||
type ReportRequest struct {
|
||||
Ident string
|
||||
ReportTasks []ReportTask
|
||||
}
|
||||
|
||||
type AssignTask struct {
|
||||
Id int64
|
||||
Clock int64
|
||||
Action string
|
||||
}
|
||||
|
||||
type ReportResponse struct {
|
||||
Message string
|
||||
AssignTasks []AssignTask
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/didi/nightingale/src/toolkits/str"
|
||||
|
||||
gstr "github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type JudgeItem struct {
|
||||
Nid string `json:"nid"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Metric string `json:"metric"`
|
||||
Tags string `json:"tags"`
|
||||
TagsMap map[string]string `json:"tagsMap"`
|
||||
Value float64 `json:"value"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Sid int64 `json:"sid"`
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
func (j *JudgeItem) PrimaryKey() string {
|
||||
return str.PK(j.Nid, j.Endpoint, j.Metric, j.Tags)
|
||||
}
|
||||
|
||||
func (j *JudgeItem) MD5() string {
|
||||
return gstr.MD5(str.PK(strconv.FormatInt(j.Sid, 16), j.Nid, j.Endpoint, j.Metric, str.SortedTags(j.TagsMap)))
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dataobj
|
||||
|
||||
type Message struct {
|
||||
Tos []string `json:"tos"`
|
||||
Subject string `json:"subject"`
|
||||
Content string `json:"content"`
|
||||
}
|
|
@ -0,0 +1,417 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
GAUGE = "GAUGE"
|
||||
COUNTER = "COUNTER"
|
||||
SUBTRACT = "SUBTRACT"
|
||||
DERIVE = "DERIVE"
|
||||
SPLIT = "/"
|
||||
)
|
||||
|
||||
const (
|
||||
MachineDep = 1
|
||||
MachineIndep = 2
|
||||
)
|
||||
|
||||
type MetricValue struct {
|
||||
Nid string `json:"nid"`
|
||||
Metric string `json:"metric"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Step int64 `json:"step"`
|
||||
ValueUntyped interface{} `json:"value"`
|
||||
Value float64 `json:"-"`
|
||||
CounterType string `json:"counterType"`
|
||||
Tags string `json:"tags"`
|
||||
TagsMap map[string]string `json:"tagsMap"` //保留2种格式,方便后端组件使用
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
var bufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
func (m *MetricValue) PK() string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if m.TagsMap == nil || len(m.TagsMap) == 0 {
|
||||
ret.WriteString(m.Endpoint)
|
||||
ret.WriteString(SPLIT)
|
||||
ret.WriteString(m.Metric)
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
ret.WriteString(m.Endpoint)
|
||||
ret.WriteString(SPLIT)
|
||||
ret.WriteString(m.Metric)
|
||||
ret.WriteString(SPLIT)
|
||||
ret.WriteString(SortedTags(m.TagsMap))
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func (m *MetricValue) CheckValidity(now int64) (err error) {
|
||||
if m == nil {
|
||||
err = fmt.Errorf("item is nil")
|
||||
return
|
||||
}
|
||||
|
||||
if m.Nid == "" && m.Endpoint == "" {
|
||||
err = fmt.Errorf("nid or endpoint should not be empty")
|
||||
return
|
||||
}
|
||||
|
||||
if m.Metric == "" {
|
||||
err = fmt.Errorf("metric should not be empty")
|
||||
return
|
||||
}
|
||||
|
||||
// 检测保留字
|
||||
reservedWords := "[\\t] [\\r] [\\n] [,] [ ] [=]"
|
||||
if HasReservedWords(m.Metric) {
|
||||
err = fmt.Errorf("metric:%s contains reserved words: %s", m.Metric, reservedWords)
|
||||
return
|
||||
}
|
||||
if HasReservedWords(m.Endpoint) {
|
||||
err = fmt.Errorf("endpoint:%s contains reserved words: %s", m.Endpoint, reservedWords)
|
||||
return
|
||||
}
|
||||
|
||||
if m.CounterType == "" {
|
||||
m.CounterType = GAUGE
|
||||
}
|
||||
|
||||
if m.CounterType != GAUGE && m.CounterType != COUNTER && m.CounterType != SUBTRACT {
|
||||
err = fmt.Errorf("wrong counter type")
|
||||
return
|
||||
}
|
||||
|
||||
if m.ValueUntyped == "" {
|
||||
err = fmt.Errorf("value is nil")
|
||||
return
|
||||
}
|
||||
|
||||
if m.Step <= 0 {
|
||||
err = fmt.Errorf("step should larger than 0")
|
||||
return
|
||||
}
|
||||
|
||||
if len(m.TagsMap) == 0 {
|
||||
m.TagsMap, err = SplitTagsString(m.Tags)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.TagsMap) > 20 {
|
||||
err = fmt.Errorf("tagkv count is too large > 20")
|
||||
}
|
||||
|
||||
if len(m.Metric) > 128 {
|
||||
err = fmt.Errorf("len(m.Metric) is too large")
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range m.TagsMap {
|
||||
delete(m.TagsMap, k)
|
||||
k = filterString(k)
|
||||
v = filterString(v)
|
||||
if len(k) == 0 || len(v) == 0 {
|
||||
err = fmt.Errorf("tag key and value should not be empty")
|
||||
return
|
||||
}
|
||||
|
||||
m.TagsMap[k] = v
|
||||
}
|
||||
|
||||
m.Tags = SortedTags(m.TagsMap)
|
||||
if len(m.Tags) > 512 {
|
||||
err = fmt.Errorf("len(m.Tags) is too large")
|
||||
return
|
||||
}
|
||||
|
||||
//时间超前5分钟则报错
|
||||
if m.Timestamp-now > 300 {
|
||||
err = fmt.Errorf("point timestamp:%d is ahead of now:%d", m.Timestamp, now)
|
||||
return
|
||||
}
|
||||
|
||||
if m.Timestamp <= 0 {
|
||||
m.Timestamp = now
|
||||
}
|
||||
|
||||
m.Timestamp = alignTs(m.Timestamp, int64(m.Step))
|
||||
|
||||
valid := true
|
||||
var vv float64
|
||||
|
||||
switch cv := m.ValueUntyped.(type) {
|
||||
case string:
|
||||
vv, err = strconv.ParseFloat(cv, 64)
|
||||
if err != nil {
|
||||
valid = false
|
||||
}
|
||||
case float64:
|
||||
vv = cv
|
||||
case uint64:
|
||||
vv = float64(cv)
|
||||
case int64:
|
||||
vv = float64(cv)
|
||||
case int:
|
||||
vv = float64(cv)
|
||||
default:
|
||||
valid = false
|
||||
}
|
||||
|
||||
if !valid {
|
||||
err = fmt.Errorf("value [%v] is illegal", m.Value)
|
||||
return
|
||||
}
|
||||
|
||||
m.Value = vv
|
||||
return
|
||||
}
|
||||
|
||||
func HasReservedWords(str string) bool {
|
||||
idx := strings.IndexFunc(str, func(r rune) bool {
|
||||
return r == '\t' ||
|
||||
r == '\r' ||
|
||||
r == '\n' ||
|
||||
r == ',' ||
|
||||
r == ' ' ||
|
||||
r == '='
|
||||
})
|
||||
return idx != -1
|
||||
}
|
||||
|
||||
func filterString(str string) string {
|
||||
if -1 == strings.IndexFunc(str,
|
||||
func(r rune) bool {
|
||||
return r == '\t' ||
|
||||
r == '\r' ||
|
||||
r == '\n' ||
|
||||
r == ',' ||
|
||||
r == ' ' ||
|
||||
r == '='
|
||||
}) {
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
return strings.Map(func(r rune) rune {
|
||||
if r == '\t' ||
|
||||
r == '\r' ||
|
||||
r == '\n' ||
|
||||
r == ',' ||
|
||||
r == ' ' ||
|
||||
r == '=' {
|
||||
return '_'
|
||||
}
|
||||
return r
|
||||
}, str)
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func SortedTags(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
size := len(tags)
|
||||
if size == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if size == 1 {
|
||||
for k, v := range tags {
|
||||
ret.WriteString(k)
|
||||
ret.WriteString("=")
|
||||
ret.WriteString(v)
|
||||
}
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
keys := make([]string, size)
|
||||
i := 0
|
||||
for k := range tags {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for j, key := range keys {
|
||||
ret.WriteString(key)
|
||||
ret.WriteString("=")
|
||||
ret.WriteString(tags[key])
|
||||
if j != size-1 {
|
||||
ret.WriteString(",")
|
||||
}
|
||||
}
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func SplitTagsString(s string) (tags map[string]string, err error) {
|
||||
tags = make(map[string]string)
|
||||
|
||||
s = strings.Replace(s, " ", "", -1)
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
|
||||
tagSlice := strings.Split(s, ",")
|
||||
for _, tag := range tagSlice {
|
||||
tagPair := strings.SplitN(tag, "=", 2)
|
||||
if len(tagPair) == 2 {
|
||||
tags[tagPair[0]] = tagPair[1]
|
||||
} else {
|
||||
err = fmt.Errorf("bad tag %s", tag)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func DictedTagstring(s string) map[string]string {
|
||||
if s == "" {
|
||||
return map[string]string{}
|
||||
}
|
||||
s = strings.Replace(s, " ", "", -1)
|
||||
|
||||
result := make(map[string]string)
|
||||
tags := strings.Split(s, ",")
|
||||
for _, tag := range tags {
|
||||
pair := strings.SplitN(tag, "=", 2)
|
||||
if len(pair) == 2 {
|
||||
result[pair[0]] = pair[1]
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func PKWithCounter(endpoint, counter string) string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
ret.WriteString(endpoint)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(counter)
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func GetCounter(metric, tag string, tagMap map[string]string) (counter string, err error) {
|
||||
if tagMap == nil {
|
||||
tagMap, err = SplitTagsString(tag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
tagStr := SortedTags(tagMap)
|
||||
counter = PKWithTags(metric, tagStr)
|
||||
return
|
||||
}
|
||||
|
||||
func PKWithTags(metric, tags string) string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if tags == "" {
|
||||
ret.WriteString(metric)
|
||||
return ret.String()
|
||||
}
|
||||
ret.WriteString(metric)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(tags)
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func PKWhitEndpointAndTags(endpoint, metric, tags string) string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if tags == "" {
|
||||
ret.WriteString(endpoint)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(metric)
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
ret.WriteString(endpoint)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(metric)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(tags)
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
// e.g. tcp.port.listen or proc.num
|
||||
type BuiltinMetric struct {
|
||||
Metric string
|
||||
Tags string
|
||||
}
|
||||
|
||||
func (bm *BuiltinMetric) String() string {
|
||||
return fmt.Sprintf("%s/%s", bm.Metric, bm.Tags)
|
||||
}
|
||||
|
||||
type BuiltinMetricRequest struct {
|
||||
Ty int
|
||||
IP string
|
||||
Checksum string
|
||||
}
|
||||
|
||||
type BuiltinMetricResponse struct {
|
||||
Metrics []*BuiltinMetric
|
||||
Checksum string
|
||||
Timestamp int64
|
||||
ErrCode int
|
||||
}
|
||||
|
||||
func (br *BuiltinMetricResponse) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<Metrics:%v, Checksum:%s, Timestamp:%v>",
|
||||
br.Metrics,
|
||||
br.Checksum,
|
||||
br.Timestamp,
|
||||
)
|
||||
}
|
||||
|
||||
type BuiltinMetricSlice []*BuiltinMetric
|
||||
|
||||
func (bm BuiltinMetricSlice) Len() int {
|
||||
return len(bm)
|
||||
}
|
||||
func (bm BuiltinMetricSlice) Swap(i, j int) {
|
||||
bm[i], bm[j] = bm[j], bm[i]
|
||||
}
|
||||
func (bm BuiltinMetricSlice) Less(i, j int) bool {
|
||||
return bm[i].String() < bm[j].String()
|
||||
}
|
||||
|
||||
func alignTs(ts int64, period int64) int64 {
|
||||
return ts - ts%period
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package dataobj
|
||||
|
||||
import "fmt"
|
||||
|
||||
// code == 0 => success
|
||||
// code == 1 => bad request
|
||||
type SimpleRpcResponse struct {
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
type NullRpcRequest struct {
|
||||
}
|
||||
|
||||
type TransferResp struct {
|
||||
Msg string
|
||||
Total int
|
||||
Invalid int
|
||||
Latency int64
|
||||
}
|
||||
|
||||
func (t *TransferResp) String() string {
|
||||
s := fmt.Sprintf("TransferResp total=%d, err_invalid=%d, latency=%dms",
|
||||
t.Total, t.Invalid, t.Latency)
|
||||
if t.Msg != "" {
|
||||
s = fmt.Sprintf("%s, msg=%s", s, t.Msg)
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OpenTsdbItem struct {
|
||||
Metric string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Value float64 `json:"value"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func (t *OpenTsdbItem) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<Metric:%s, Tags:%v, Value:%v, TS:%d>",
|
||||
t.Metric,
|
||||
t.Tags,
|
||||
t.Value,
|
||||
t.Timestamp,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *OpenTsdbItem) OpenTsdbString() (s string) {
|
||||
s = fmt.Sprintf("put %s %d %.3f ", t.Metric, t.Timestamp, t.Value)
|
||||
|
||||
for k, v := range t.Tags {
|
||||
key := strings.ToLower(strings.Replace(k, " ", "_", -1))
|
||||
value := strings.Replace(v, " ", "_", -1)
|
||||
s += key + "=" + value + " "
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package dataobj
|
||||
|
||||
type QueryData struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
ConsolFunc string `json:"consolFunc"`
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Nids []string `json:"nids"`
|
||||
Counters []string `json:"counters"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
}
|
||||
|
||||
type QueryDataForUI struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Metric string `json:"metric"`
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Nids []string `json:"nids"`
|
||||
Tags []string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
GroupKey []string `json:"groupKey"` //聚合维度
|
||||
AggrFunc string `json:"aggrFunc"` //聚合计算
|
||||
ConsolFunc string `json:"consolFunc"`
|
||||
Comparisons []int64 `json:"comparisons"` //环比多少时间
|
||||
}
|
||||
|
||||
type QueryDataForUIResp struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Nid string `json:"nid"`
|
||||
Counter string `json:"counter"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Values []*RRDData `json:"values"`
|
||||
Comparison int64 `json:"comparison"`
|
||||
}
|
||||
|
||||
type QueryDataResp struct {
|
||||
Data []*TsdbQueryResponse
|
||||
Msg string
|
||||
}
|
||||
|
||||
// judge 数据层 必须
|
||||
func (req *QueryData) Key() string {
|
||||
return req.Endpoints[0] + "/" + req.Counters[0]
|
||||
}
|
||||
|
||||
func (resp *TsdbQueryResponse) Key() string {
|
||||
return resp.Endpoint + "/" + resp.Counter
|
||||
}
|
||||
|
||||
type EndpointsRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
}
|
||||
|
||||
type MetricResp struct {
|
||||
Metrics []string `json:"metrics"`
|
||||
}
|
||||
|
||||
type EndpointMetricRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metrics []string `json:"metrics"`
|
||||
}
|
||||
|
||||
type IndexTagkvResp struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tagkv []*TagPair `json:"tagkv"`
|
||||
}
|
||||
|
||||
type TagPair struct {
|
||||
Key string `json:"tagk"` // json 和变量不一致为了兼容前端
|
||||
Values []string `json:"tagv"`
|
||||
}
|
||||
|
||||
type CludeRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Include []*TagPair `json:"include"`
|
||||
Exclude []*TagPair `json:"exclude"`
|
||||
}
|
||||
|
||||
type XcludeResp struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tags []string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
}
|
||||
|
||||
type IndexByFullTagsRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tagkv []TagPair `json:"tagkv"`
|
||||
}
|
||||
|
||||
type IndexByFullTagsResp struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tags []string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package dataobj
|
||||
|
||||
type File struct {
|
||||
Key interface{}
|
||||
Filename string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
type RRDFileResp struct {
|
||||
Files []File
|
||||
Msg string
|
||||
}
|
||||
|
||||
type RRDFileQuery struct {
|
||||
Files []RRDFile
|
||||
}
|
||||
|
||||
type RRDFile struct {
|
||||
Key interface{}
|
||||
Filename string
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dataobj
|
||||
|
||||
type Notify struct {
|
||||
Tos []string `json:"tos"`
|
||||
Subject string `json:"subject,omitempty"`
|
||||
Content string `json:"content"`
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
COMMON_MODULE = "common"
|
||||
)
|
||||
|
||||
type IPAndSnmp struct {
|
||||
IP string `json:"ip"`
|
||||
Module string `json:"module"`
|
||||
Version string `json:"version"`
|
||||
Auth string `json:"auth"`
|
||||
Region string `json:"region"`
|
||||
Step int `json:"step"`
|
||||
Timeout int `json:"timeout"`
|
||||
Port int `json:"port"`
|
||||
Metric Metric `json:"metric"`
|
||||
LastUpdated time.Time `json:"last_updated"`
|
||||
}
|
||||
|
||||
type Metric struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Oid string `yaml:"oid" json:"oid"`
|
||||
Type string `yaml:"type" json:"type"`
|
||||
Help string `yaml:"help" json:"help"`
|
||||
Indexes []*Index `yaml:"indexes" json:"indexes,omitempty"`
|
||||
Lookups []*Lookup `yaml:"lookups" json:"lookups,omitempty"`
|
||||
RegexpExtracts map[string][]RegexpExtract `yaml:"regex_extracts" json:"regex_extracts,omitempty"`
|
||||
EnumValues map[int]string `yaml:"enum_values" json:"enum_values,omitempty"`
|
||||
}
|
||||
|
||||
type Index struct {
|
||||
Labelname string `yaml:"labelname" json:"labelname"`
|
||||
Type string `yaml:"type" json:"type"`
|
||||
FixedSize int `yaml:"fixed_size" json:"fixed_size,omitempty"`
|
||||
Implied bool `yaml:"implied" json:"implied,omitempty"`
|
||||
}
|
||||
|
||||
type Lookup struct {
|
||||
Labels []string `yaml:"labels" json:"labels"`
|
||||
Labelname string `yaml:"labelname" json:"labelname"`
|
||||
Oid string `yaml:"oid" json:"oid,omitempty"`
|
||||
Type string `yaml:"type" json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type RegexpExtract struct {
|
||||
Value string `yaml:"value" json:"value"`
|
||||
Regex Regexp `yaml:"regex" json:"regex"`
|
||||
}
|
||||
|
||||
// Regexp encapsulates a regexp.Regexp and makes it YAML marshalable.
|
||||
type Regexp struct {
|
||||
*regexp.Regexp
|
||||
}
|
||||
|
||||
type IfTags struct {
|
||||
IfName string
|
||||
IfIndex string
|
||||
}
|
||||
|
||||
// Secret is a string that must not be revealed on marshaling.
|
||||
type Secret string
|
||||
|
||||
type Auth struct {
|
||||
Community Secret `json:"community,omitempty"`
|
||||
SecurityLevel string `json:"security_level,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password Secret `json:"password,omitempty"`
|
||||
AuthProtocol string `json:"auth_protocol,omitempty"`
|
||||
PrivProtocol string `json:"priv_protocol,omitempty"`
|
||||
PrivPassword Secret `json:"priv_password,omitempty"`
|
||||
ContextName string `json:"context_name,omitempty"`
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/toolkits/str"
|
||||
)
|
||||
|
||||
type JsonFloat float64
|
||||
|
||||
func (v JsonFloat) MarshalJSON() ([]byte, error) {
|
||||
f := float64(v)
|
||||
if math.IsNaN(f) || math.IsInf(f, 0) {
|
||||
return []byte("null"), nil
|
||||
} else {
|
||||
return []byte(fmt.Sprintf("%f", f)), nil
|
||||
}
|
||||
}
|
||||
|
||||
type RRDData struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Value JsonFloat `json:"value"`
|
||||
}
|
||||
|
||||
type RRDValues []*RRDData
|
||||
|
||||
func (r RRDValues) Len() int { return len(r) }
|
||||
func (r RRDValues) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r RRDValues) Less(i, j int) bool { return r[i].Timestamp < r[j].Timestamp }
|
||||
|
||||
func NewRRDData(ts int64, val float64) *RRDData {
|
||||
return &RRDData{Timestamp: ts, Value: JsonFloat(val)}
|
||||
}
|
||||
|
||||
func (rrd *RRDData) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<RRDData:Value:%v TS:%d %v>",
|
||||
rrd.Value,
|
||||
rrd.Timestamp,
|
||||
time.Unix(rrd.Timestamp, 0).Format("2006-01-02 15:04:05"),
|
||||
)
|
||||
}
|
||||
|
||||
type TsdbQueryResponse struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Nid string `json:"nid"`
|
||||
Counter string `json:"counter"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Values []*RRDData `json:"values"`
|
||||
}
|
||||
|
||||
type TsdbItem struct {
|
||||
Nid string `json:"nid"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Metric string `json:"metric"`
|
||||
Tags string `json:"tags"`
|
||||
TagsMap map[string]string `json:"tagsMap"`
|
||||
Value float64 `json:"value"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Heartbeat int `json:"heartbeat"`
|
||||
Min string `json:"min"`
|
||||
Max string `json:"max"`
|
||||
From int `json:"from"`
|
||||
}
|
||||
|
||||
const GRAPH = 1
|
||||
|
||||
func (t *TsdbItem) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<Endpoint:%s, Metric:%s, Tags:%v, TagsMap:%v, Value:%v, TS:%d %v DsType:%s, Step:%d, Heartbeat:%d, Min:%s, Max:%s>",
|
||||
t.Endpoint,
|
||||
t.Metric,
|
||||
t.Tags,
|
||||
t.TagsMap,
|
||||
t.Value,
|
||||
t.Timestamp,
|
||||
str.UnixTsFormat(t.Timestamp),
|
||||
t.DsType,
|
||||
t.Step,
|
||||
t.Heartbeat,
|
||||
t.Min,
|
||||
t.Max,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *TsdbItem) PrimaryKey() string {
|
||||
return str.PK(t.Endpoint, t.Metric, t.Tags)
|
||||
}
|
||||
|
||||
func (t *TsdbItem) MD5() string {
|
||||
return str.MD5(t.Endpoint, t.Metric, str.SortedTags(t.TagsMap))
|
||||
}
|
||||
|
||||
func (t *TsdbItem) UUID() string {
|
||||
return str.UUID(t.Endpoint, t.Metric, t.Tags, t.DsType, t.Step)
|
||||
}
|
||||
|
||||
// ConsolFunc 是RRD中的概念,比如:MIN|MAX|AVERAGE
|
||||
type TsdbQueryParam struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
ConsolFunc string `json:"consolFunc"`
|
||||
Nid string `json:"nid"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Counter string `json:"counter"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dsType"`
|
||||
}
|
||||
|
||||
func (g *TsdbQueryParam) PK() string {
|
||||
return PKWithCounter(g.Endpoint, g.Counter)
|
||||
}
|
||||
|
||||
func NidToEndpoint(nid string) string {
|
||||
endpoint := "__nid__" + nid + "__"
|
||||
return endpoint
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package identity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/toolkits/pkg/file"
|
||||
"github.com/toolkits/pkg/sys"
|
||||
)
|
||||
|
||||
type Identity struct {
|
||||
IP shell `yaml:"ip"`
|
||||
Ident shell `yaml:"ident"`
|
||||
}
|
||||
|
||||
type shell struct {
|
||||
Specify string `yaml:"specify"`
|
||||
Shell string `yaml:"shell"`
|
||||
}
|
||||
|
||||
var config Identity
|
||||
|
||||
func Parse() error {
|
||||
yml := getIdentityYmlFile()
|
||||
if yml == "" {
|
||||
return fmt.Errorf("etc/identity[.local].yml not found")
|
||||
}
|
||||
|
||||
var i Identity
|
||||
if err := file.ReadYaml(yml, &i); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config = i
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetIP() (string, error) {
|
||||
return getByShell(config.IP)
|
||||
}
|
||||
|
||||
func GetIdent() (string, error) {
|
||||
return getByShell(config.Ident)
|
||||
}
|
||||
|
||||
func getByShell(s shell) (string, error) {
|
||||
if s.Specify != "" {
|
||||
return s.Specify, nil
|
||||
}
|
||||
|
||||
out, err := sys.CmdOutTrim("sh", "-c", s.Shell)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if strings.Contains(out, " ") {
|
||||
return "", fmt.Errorf("output: %s invalid", out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func getIdentityYmlFile() string {
|
||||
yml := "etc/identity.local.yml"
|
||||
if file.IsExist(yml) {
|
||||
return yml
|
||||
}
|
||||
|
||||
yml = "etc/identity.yml"
|
||||
if file.IsExist(yml) {
|
||||
return yml
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package loggeri
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Dir string `yaml:"dir"`
|
||||
Level string `yaml:"level"`
|
||||
KeepHours uint `yaml:"keepHours"`
|
||||
}
|
||||
|
||||
// InitLogger init logger toolkit
|
||||
func Init(c Config) {
|
||||
lb, err := logger.NewFileBackend(c.Dir)
|
||||
if err != nil {
|
||||
fmt.Println("cannot init logger:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
lb.SetRotateByHour(true)
|
||||
lb.SetKeepHours(c.KeepHours)
|
||||
|
||||
logger.SetLogging(c.Level, lb)
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
type consoleColorModeValue int
|
||||
|
||||
const (
|
||||
autoColor consoleColorModeValue = iota
|
||||
disableColor
|
||||
forceColor
|
||||
)
|
||||
|
||||
var (
|
||||
green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
|
||||
white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
|
||||
yellow = string([]byte{27, 91, 57, 48, 59, 52, 51, 109})
|
||||
red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
|
||||
blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
|
||||
magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
|
||||
cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
|
||||
reset = string([]byte{27, 91, 48, 109})
|
||||
consoleColorMode = autoColor
|
||||
)
|
||||
|
||||
// LoggerConfig defines the config for Logger middleware.
|
||||
type LoggerConfig struct {
|
||||
// Optional. Default value is gin.defaultLogFormatter
|
||||
Formatter LogFormatter
|
||||
|
||||
// Output is a writer where logs are written.
|
||||
// Optional. Default value is gin.DefaultWriter.
|
||||
Output io.Writer
|
||||
|
||||
// SkipPaths is a url path array which logs are not written.
|
||||
// Optional.
|
||||
SkipPaths []string
|
||||
}
|
||||
|
||||
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
|
||||
type LogFormatter func(params LogFormatterParams) string
|
||||
|
||||
// LogFormatterParams is the structure any formatter will be handed when time to log comes
|
||||
type LogFormatterParams struct {
|
||||
Request *http.Request
|
||||
|
||||
// TimeStamp shows the time after the server returns a response.
|
||||
TimeStamp time.Time
|
||||
// StatusCode is HTTP response code.
|
||||
StatusCode int
|
||||
// Latency is how much time the server cost to process a certain request.
|
||||
Latency time.Duration
|
||||
// ClientIP equals Context's ClientIP method.
|
||||
ClientIP string
|
||||
// Method is the HTTP method given to the request.
|
||||
Method string
|
||||
// Path is a path the client requests.
|
||||
Path string
|
||||
// ErrorMessage is set if error has occurred in processing the request.
|
||||
ErrorMessage string
|
||||
// isTerm shows whether does gin's output descriptor refers to a terminal.
|
||||
isTerm bool
|
||||
// BodySize is the size of the Response Body
|
||||
BodySize int
|
||||
// Keys are the keys set on the request's context.
|
||||
Keys map[string]interface{}
|
||||
}
|
||||
|
||||
// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal.
|
||||
func (p *LogFormatterParams) StatusCodeColor() string {
|
||||
code := p.StatusCode
|
||||
|
||||
switch {
|
||||
case code >= http.StatusOK && code < http.StatusMultipleChoices:
|
||||
return green
|
||||
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
|
||||
return white
|
||||
case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
|
||||
return yellow
|
||||
default:
|
||||
return red
|
||||
}
|
||||
}
|
||||
|
||||
// MethodColor is the ANSI color for appropriately logging http method to a terminal.
|
||||
func (p *LogFormatterParams) MethodColor() string {
|
||||
method := p.Method
|
||||
|
||||
switch method {
|
||||
case "GET":
|
||||
return blue
|
||||
case "POST":
|
||||
return cyan
|
||||
case "PUT":
|
||||
return yellow
|
||||
case "DELETE":
|
||||
return red
|
||||
case "PATCH":
|
||||
return green
|
||||
case "HEAD":
|
||||
return magenta
|
||||
case "OPTIONS":
|
||||
return white
|
||||
default:
|
||||
return reset
|
||||
}
|
||||
}
|
||||
|
||||
// ResetColor resets all escape attributes.
|
||||
func (p *LogFormatterParams) ResetColor() string {
|
||||
return reset
|
||||
}
|
||||
|
||||
// IsOutputColor indicates whether can colors be outputted to the log.
|
||||
func (p *LogFormatterParams) IsOutputColor() bool {
|
||||
return consoleColorMode == forceColor || (consoleColorMode == autoColor && p.isTerm)
|
||||
}
|
||||
|
||||
// defaultLogFormatter is the default log format function Logger middleware uses.
|
||||
var defaultLogFormatter = func(param LogFormatterParams) string {
|
||||
var statusColor, methodColor, resetColor string
|
||||
if param.IsOutputColor() {
|
||||
statusColor = param.StatusCodeColor()
|
||||
methodColor = param.MethodColor()
|
||||
resetColor = param.ResetColor()
|
||||
}
|
||||
|
||||
if param.Latency > time.Minute {
|
||||
// Truncate in a golang < 1.8 safe way
|
||||
param.Latency = param.Latency - param.Latency%time.Second
|
||||
}
|
||||
return fmt.Sprintf("[GIN] |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s",
|
||||
statusColor, param.StatusCode, resetColor,
|
||||
param.Latency,
|
||||
param.ClientIP,
|
||||
methodColor, param.Method, resetColor,
|
||||
param.Path,
|
||||
param.ErrorMessage,
|
||||
)
|
||||
}
|
||||
|
||||
// DisableConsoleColor disables color output in the console.
|
||||
func DisableConsoleColor() {
|
||||
consoleColorMode = disableColor
|
||||
}
|
||||
|
||||
// ForceConsoleColor force color output in the console.
|
||||
func ForceConsoleColor() {
|
||||
consoleColorMode = forceColor
|
||||
}
|
||||
|
||||
// ErrorLogger returns a handlerfunc for any error type.
|
||||
func ErrorLogger() gin.HandlerFunc {
|
||||
return ErrorLoggerT(gin.ErrorTypeAny)
|
||||
}
|
||||
|
||||
// ErrorLoggerT returns a handlerfunc for a given error type.
|
||||
func ErrorLoggerT(typ gin.ErrorType) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Next()
|
||||
errors := c.Errors.ByType(typ)
|
||||
if len(errors) > 0 {
|
||||
c.JSON(-1, errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
|
||||
// By default gin.DefaultWriter = os.Stdout.
|
||||
func Logger() gin.HandlerFunc {
|
||||
return LoggerWithConfig(LoggerConfig{})
|
||||
}
|
||||
|
||||
// LoggerWithFormatter instance a Logger middleware with the specified log format function.
|
||||
func LoggerWithFormatter(f LogFormatter) gin.HandlerFunc {
|
||||
return LoggerWithConfig(LoggerConfig{
|
||||
Formatter: f,
|
||||
})
|
||||
}
|
||||
|
||||
// LoggerWithWriter instance a Logger middleware with the specified writer buffer.
|
||||
// Example: os.Stdout, a file opened in write mode, a socket...
|
||||
func LoggerWithWriter(out io.Writer, notlogged ...string) gin.HandlerFunc {
|
||||
return LoggerWithConfig(LoggerConfig{
|
||||
Output: out,
|
||||
SkipPaths: notlogged,
|
||||
})
|
||||
}
|
||||
|
||||
// LoggerWithConfig instance a Logger middleware with config.
|
||||
func LoggerWithConfig(conf LoggerConfig) gin.HandlerFunc {
|
||||
formatter := conf.Formatter
|
||||
if formatter == nil {
|
||||
formatter = defaultLogFormatter
|
||||
}
|
||||
|
||||
out := conf.Output
|
||||
if out == nil {
|
||||
out = os.Stdout
|
||||
}
|
||||
|
||||
notlogged := conf.SkipPaths
|
||||
|
||||
isTerm := true
|
||||
|
||||
if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
|
||||
(!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) {
|
||||
isTerm = false
|
||||
}
|
||||
|
||||
var skip map[string]struct{}
|
||||
|
||||
if length := len(notlogged); length > 0 {
|
||||
skip = make(map[string]struct{}, length)
|
||||
|
||||
for _, path := range notlogged {
|
||||
skip[path] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return func(c *gin.Context) {
|
||||
// Start timer
|
||||
start := time.Now()
|
||||
path := c.Request.URL.Path
|
||||
raw := c.Request.URL.RawQuery
|
||||
|
||||
var (
|
||||
rdr1 io.ReadCloser
|
||||
rdr2 io.ReadCloser
|
||||
)
|
||||
|
||||
if c.Request.Method != "GET" {
|
||||
buf, _ := ioutil.ReadAll(c.Request.Body)
|
||||
rdr1 = ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||
rdr2 = ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||
|
||||
c.Request.Body = rdr2
|
||||
}
|
||||
|
||||
// Process request
|
||||
c.Next()
|
||||
|
||||
// Log only when path is not being skipped
|
||||
if _, ok := skip[path]; !ok {
|
||||
param := LogFormatterParams{
|
||||
Request: c.Request,
|
||||
isTerm: isTerm,
|
||||
Keys: c.Keys,
|
||||
}
|
||||
|
||||
// Stop timer
|
||||
param.TimeStamp = time.Now()
|
||||
param.Latency = param.TimeStamp.Sub(start)
|
||||
|
||||
param.ClientIP = c.ClientIP()
|
||||
param.Method = c.Request.Method
|
||||
param.StatusCode = c.Writer.Status()
|
||||
param.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
|
||||
|
||||
param.BodySize = c.Writer.Size()
|
||||
|
||||
if raw != "" {
|
||||
path = path + "?" + raw
|
||||
}
|
||||
|
||||
param.Path = path
|
||||
|
||||
// fmt.Fprint(out, formatter(param))
|
||||
logger.Debug(formatter(param))
|
||||
|
||||
if c.Request.Method != "GET" {
|
||||
logger.Debug(readBody(rdr1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readBody(reader io.Reader) string {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(reader)
|
||||
|
||||
s := buf.String()
|
||||
return s
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
package middleware
|
||||
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/toolkits/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
dunno = []byte("???")
|
||||
centerDot = []byte("·")
|
||||
dot = []byte(".")
|
||||
slash = []byte("/")
|
||||
)
|
||||
|
||||
// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
|
||||
func Recovery() gin.HandlerFunc {
|
||||
return RecoveryWithWriter(gin.DefaultErrorWriter)
|
||||
}
|
||||
|
||||
// RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.
|
||||
func RecoveryWithWriter(out io.Writer) gin.HandlerFunc {
|
||||
var logger *log.Logger
|
||||
if out != nil {
|
||||
logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags)
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
// custom error
|
||||
if e, ok := err.(errors.PageError); ok {
|
||||
c.JSON(200, gin.H{"err": e.Message})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Check for a broken connection, as it is not really a
|
||||
// condition that warrants a panic stack trace.
|
||||
var brokenPipe bool
|
||||
if ne, ok := err.(*net.OpError); ok {
|
||||
if se, ok := ne.Err.(*os.SyscallError); ok {
|
||||
if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
|
||||
brokenPipe = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if logger != nil {
|
||||
stack := stack(3)
|
||||
httpRequest, _ := httputil.DumpRequest(c.Request, false)
|
||||
headers := strings.Split(string(httpRequest), "\r\n")
|
||||
for idx, header := range headers {
|
||||
current := strings.Split(header, ":")
|
||||
if current[0] == "Authorization" {
|
||||
headers[idx] = current[0] + ": *"
|
||||
}
|
||||
}
|
||||
if brokenPipe {
|
||||
logger.Printf("%s\n%s%s", err, string(httpRequest), reset)
|
||||
} else if gin.IsDebugging() {
|
||||
logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s",
|
||||
timeFormat(time.Now()), strings.Join(headers, "\r\n"), err, stack, reset)
|
||||
} else {
|
||||
logger.Printf("[Recovery] %s panic recovered:\n%s\n%s%s",
|
||||
timeFormat(time.Now()), err, stack, reset)
|
||||
}
|
||||
}
|
||||
|
||||
// If the connection is dead, we can't write a status to it.
|
||||
if brokenPipe {
|
||||
c.Error(err.(error)) // nolint: errcheck
|
||||
c.Abort()
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}()
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// stack returns a nicely formatted stack frame, skipping skip frames.
|
||||
func stack(skip int) []byte {
|
||||
buf := new(bytes.Buffer) // the returned data
|
||||
// As we loop, we open files and read them. These variables record the currently
|
||||
// loaded file.
|
||||
var lines [][]byte
|
||||
var lastFile string
|
||||
for i := skip; ; i++ { // Skip the expected number of frames
|
||||
pc, file, line, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
// Print this much at least. If we can't find the source, it won't show.
|
||||
fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
|
||||
if file != lastFile {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
lines = bytes.Split(data, []byte{'\n'})
|
||||
lastFile = file
|
||||
}
|
||||
fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// source returns a space-trimmed slice of the n'th line.
|
||||
func source(lines [][]byte, n int) []byte {
|
||||
n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
|
||||
if n < 0 || n >= len(lines) {
|
||||
return dunno
|
||||
}
|
||||
return bytes.TrimSpace(lines[n])
|
||||
}
|
||||
|
||||
// function returns, if possible, the name of the function containing the PC.
|
||||
func function(pc uintptr) []byte {
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
return dunno
|
||||
}
|
||||
name := []byte(fn.Name())
|
||||
// The name includes the path name to the package, which is unnecessary
|
||||
// since the file name is already included. Plus, it has center dots.
|
||||
// That is, we see
|
||||
// runtime/debug.*T·ptrmethod
|
||||
// and want
|
||||
// *T.ptrmethod
|
||||
// Also the package path might contains dot (e.g. code.google.com/...),
|
||||
// so first eliminate the path prefix
|
||||
if lastSlash := bytes.LastIndex(name, slash); lastSlash >= 0 {
|
||||
name = name[lastSlash+1:]
|
||||
}
|
||||
if period := bytes.Index(name, dot); period >= 0 {
|
||||
name = name[period+1:]
|
||||
}
|
||||
name = bytes.Replace(name, centerDot, dot, -1)
|
||||
return name
|
||||
}
|
||||
|
||||
func timeFormat(t time.Time) string {
|
||||
return t.Format("2006/01/02 - 15:04:05")
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/common/address"
|
||||
"github.com/didi/nightingale/src/common/identity"
|
||||
"github.com/didi/nightingale/src/models"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/net/httplib"
|
||||
)
|
||||
|
||||
type ReportSection struct {
|
||||
Mod string `yaml:"mod"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Interval int `yaml:"interval"`
|
||||
Timeout int `yaml:"timeout"`
|
||||
HTTPPort string `yaml:"http_port"`
|
||||
RPCPort string `yaml:"rpc_port"`
|
||||
Remark string `yaml:"remark"`
|
||||
}
|
||||
|
||||
var Config ReportSection
|
||||
|
||||
func Init(cfg ReportSection, mod string) {
|
||||
Config = cfg
|
||||
|
||||
addrs := address.GetHTTPAddresses(mod)
|
||||
|
||||
t1 := time.NewTicker(time.Duration(Config.Interval) * time.Millisecond)
|
||||
report(addrs)
|
||||
for {
|
||||
<-t1.C
|
||||
report(addrs)
|
||||
}
|
||||
}
|
||||
|
||||
type reportRes struct {
|
||||
Err string `json:"err"`
|
||||
Dat string `json:"dat"`
|
||||
}
|
||||
|
||||
func report(addrs []string) {
|
||||
perm := rand.Perm(len(addrs))
|
||||
for i := range perm {
|
||||
url := fmt.Sprintf("http://%s/api/hbs/heartbeat", addrs[perm[i]])
|
||||
|
||||
ident, _ := identity.GetIdent()
|
||||
m := map[string]string{
|
||||
"module": Config.Mod,
|
||||
"identity": ident,
|
||||
"rpc_port": Config.RPCPort,
|
||||
"http_port": Config.HTTPPort,
|
||||
"remark": Config.Remark,
|
||||
}
|
||||
|
||||
var body reportRes
|
||||
err := httplib.Post(url).JSONBodyQuiet(m).SetTimeout(3 * time.Second).ToJSON(&body)
|
||||
if err != nil {
|
||||
logger.Errorf("curl %s fail: %v", url, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if body.Err != "" {
|
||||
logger.Error(body.Err)
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type instanceRes struct {
|
||||
Err string `json:"err"`
|
||||
Dat []*models.Instance `json:"dat"`
|
||||
}
|
||||
|
||||
func GetAlive(wantedMod, serverMod string) ([]*models.Instance, error) {
|
||||
addrs := address.GetHTTPAddresses(serverMod)
|
||||
perm := rand.Perm(len(addrs))
|
||||
|
||||
timeout := 3000
|
||||
if Config.Timeout != 0 {
|
||||
timeout = Config.Timeout
|
||||
}
|
||||
|
||||
var body instanceRes
|
||||
var err error
|
||||
for i := range perm {
|
||||
url := fmt.Sprintf("http://%s/api/hbs/instances?mod=%s&alive=1", addrs[perm[i]], wantedMod)
|
||||
err = httplib.Get(url).SetTimeout(time.Duration(timeout) * time.Millisecond).ToJSON(&body)
|
||||
|
||||
if err != nil {
|
||||
logger.Warningf("curl %s fail: %v", url, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if body.Err != "" {
|
||||
err = fmt.Errorf("curl %s fail: %v", url, body.Err)
|
||||
logger.Warning(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return body.Dat, err
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/runner"
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Configs struct {
|
||||
Id int64
|
||||
Ckey string
|
||||
Cval string
|
||||
}
|
||||
|
||||
// InitSalt generate random salt
|
||||
func InitSalt() {
|
||||
val, err := ConfigsGet("salt")
|
||||
if err != nil {
|
||||
log.Fatalln("cannot query salt", err)
|
||||
}
|
||||
|
||||
if val != "" {
|
||||
return
|
||||
}
|
||||
|
||||
content := fmt.Sprintf("%s%d%d%s", runner.Hostname, os.Getpid(), time.Now().UnixNano(), str.RandLetters(6))
|
||||
salt := str.MD5(content)
|
||||
err = ConfigsSet("salt", salt)
|
||||
if err != nil {
|
||||
log.Fatalln("init salt in mysql", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ConfigsGet(ckey string) (string, error) {
|
||||
var obj Configs
|
||||
has, err := DB["rdb"].Where("ckey=?", ckey).Get(&obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return obj.Cval, nil
|
||||
}
|
||||
|
||||
func ConfigsSet(ckey, cval string) error {
|
||||
var obj Configs
|
||||
has, err := DB["rdb"].Where("ckey=?", ckey).Get(&obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has {
|
||||
_, err = DB["rdb"].Insert(Configs{
|
||||
Ckey: ckey,
|
||||
Cval: cval,
|
||||
})
|
||||
} else {
|
||||
obj.Cval = cval
|
||||
_, err = DB["rdb"].Where("ckey=?", ckey).Cols("cval").Update(obj)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func ConfigsGets(ckeys []string) (map[string]string, error) {
|
||||
var objs []Configs
|
||||
err := DB["rdb"].In("ckey", ckeys).Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count := len(ckeys)
|
||||
kvmap := make(map[string]string, count)
|
||||
for i := 0; i < count; i++ {
|
||||
kvmap[ckeys[i]] = ""
|
||||
}
|
||||
|
||||
for i := 0; i < len(objs); i++ {
|
||||
kvmap[objs[i].Ckey] = objs[i].Cval
|
||||
}
|
||||
|
||||
return kvmap, nil
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package models
|
||||
|
||||
const InnerTenantIdent = "inner"
|
|
@ -0,0 +1,164 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Host struct {
|
||||
Id int64 `json:"id"`
|
||||
SN string `json:"sn" xorm:"'sn'"`
|
||||
IP string `json:"ip" xorm:"'ip'"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
Note string `json:"note"`
|
||||
CPU string `json:"cpu" xorm:"'cpu'"`
|
||||
Mem string `json:"mem"`
|
||||
Disk string `json:"disk"`
|
||||
Cate string `json:"cate"`
|
||||
Clock int64 `json:"clock"`
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
func (h *Host) Save() error {
|
||||
_, err := DB["ams"].Insert(h)
|
||||
return err
|
||||
}
|
||||
|
||||
func HostNew(sn, ip, ident, name, cate string, fields map[string]interface{}) error {
|
||||
host := new(Host)
|
||||
host.SN = sn
|
||||
host.IP = ip
|
||||
host.Ident = ident
|
||||
host.Name = name
|
||||
host.Cate = cate
|
||||
host.Clock = time.Now().Unix()
|
||||
|
||||
session := DB["ams"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Insert(host); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if len(fields) > 0 {
|
||||
if _, err := session.Table(new(Host)).ID(host.Id).Update(fields); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (h *Host) Update(fields map[string]interface{}) error {
|
||||
_, err := DB["ams"].Table(new(Host)).ID(h.Id).Update(fields)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *Host) Del() error {
|
||||
_, err := DB["ams"].Where("id=?", h.Id).Delete(new(Host))
|
||||
return err
|
||||
}
|
||||
|
||||
func HostUpdateNote(ids []int64, note string) error {
|
||||
_, err := DB["ams"].Exec("UPDATE host SET note=? WHERE id in ("+str.IdsString(ids)+")", note)
|
||||
return err
|
||||
}
|
||||
|
||||
func HostUpdateCate(ids []int64, cate string) error {
|
||||
_, err := DB["ams"].Exec("UPDATE host SET cate=? WHERE id in ("+str.IdsString(ids)+")", cate)
|
||||
return err
|
||||
}
|
||||
|
||||
func HostUpdateTenant(ids []int64, tenant string) error {
|
||||
_, err := DB["ams"].Exec("UPDATE host SET tenant=? WHERE id in ("+str.IdsString(ids)+")", tenant)
|
||||
return err
|
||||
}
|
||||
|
||||
func HostGet(where string, args ...interface{}) (*Host, error) {
|
||||
var obj Host
|
||||
has, err := DB["ams"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func HostGets(where string, args ...interface{}) (hosts []Host, err error) {
|
||||
if where != "" {
|
||||
err = DB["ams"].Where(where, args...).Find(&hosts)
|
||||
} else {
|
||||
err = DB["ams"].Find(&hosts)
|
||||
}
|
||||
return hosts, err
|
||||
}
|
||||
|
||||
func HostByIds(ids []int64) (hosts []Host, err error) {
|
||||
if len(ids) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
err = DB["ams"].In("id", ids).Find(&hosts)
|
||||
return
|
||||
}
|
||||
|
||||
func HostSearch(batch, field string) ([]Host, error) {
|
||||
arr := str.ParseLines(strings.Replace(batch, ",", "\n", -1))
|
||||
if len(arr) == 0 {
|
||||
return []Host{}, nil
|
||||
}
|
||||
|
||||
var objs []Host
|
||||
err := DB["ams"].In(field, arr).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func HostTotalForAdmin(tenant, query, batch, field string) (int64, error) {
|
||||
return buildHostWhere(tenant, query, batch, field).Count()
|
||||
}
|
||||
|
||||
func HostGetsForAdmin(tenant, query, batch, field string, limit, offset int) ([]Host, error) {
|
||||
var objs []Host
|
||||
err := buildHostWhere(tenant, query, batch, field).Limit(limit, offset).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func buildHostWhere(tenant, query, batch, field string) *xorm.Session {
|
||||
session := DB["ams"].Table(new(Host)).OrderBy("ident")
|
||||
|
||||
if tenant != "" {
|
||||
session = session.Where("tenant=?", tenant)
|
||||
}
|
||||
|
||||
if batch == "" && query != "" {
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
q := "%" + arr[i] + "%"
|
||||
session = session.Where("cate=? or sn=? or ident like ? or ip like ? or name like ? or note like ?", arr[i], arr[i], q, q, q, q)
|
||||
}
|
||||
}
|
||||
|
||||
if batch != "" {
|
||||
arr := str.ParseLines(strings.Replace(batch, ",", "\n", -1))
|
||||
if len(arr) > 0 {
|
||||
session = session.In(field, arr)
|
||||
}
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/cache"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cache.InitMemoryCache(time.Hour)
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Invite struct {
|
||||
Id int64
|
||||
Token string
|
||||
Expire int64
|
||||
Creator string
|
||||
}
|
||||
|
||||
func InviteGet(where string, args ...interface{}) (*Invite, error) {
|
||||
var obj Invite
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func InviteNew(token, creator string) error {
|
||||
now := time.Now().Unix()
|
||||
obj := Invite{
|
||||
Token: token,
|
||||
Creator: creator,
|
||||
Expire: now + 3600*24,
|
||||
}
|
||||
_, err := DB["rdb"].Insert(obj)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/ldap.v3"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/rdb/config"
|
||||
)
|
||||
|
||||
func genLdapAttributeSearchList() []string {
|
||||
var ldapAttributes []string
|
||||
attrs := config.Config.LDAP.Attributes
|
||||
if attrs.Dispname != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Dispname)
|
||||
}
|
||||
if attrs.Email != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Email)
|
||||
}
|
||||
if attrs.Phone != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Phone)
|
||||
}
|
||||
if attrs.Im != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Im)
|
||||
}
|
||||
return ldapAttributes
|
||||
}
|
||||
|
||||
func ldapReq(user, pass string) (*ldap.SearchResult, error) {
|
||||
var conn *ldap.Conn
|
||||
var err error
|
||||
lc := config.Config.LDAP
|
||||
addr := fmt.Sprintf("%s:%d", lc.Host, lc.Port)
|
||||
|
||||
if lc.TLS {
|
||||
conn, err = ldap.DialTLS("tcp", addr, &tls.Config{InsecureSkipVerify: true})
|
||||
} else {
|
||||
conn, err = ldap.Dial("tcp", addr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot dial ldap: %v", err)
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if !lc.TLS && lc.StartTLS {
|
||||
if err := conn.StartTLS(&tls.Config{InsecureSkipVerify: true}); err != nil {
|
||||
return nil, fmt.Errorf("ldap.conn startTLS fail: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// if bindUser is empty, anonymousSearch mode
|
||||
if lc.BindUser != "" {
|
||||
// BindSearch mode
|
||||
if err := conn.Bind(lc.BindUser, lc.BindPass); err != nil {
|
||||
return nil, fmt.Errorf("bind ldap fail: %v, use %s", err, lc.BindUser)
|
||||
}
|
||||
}
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
lc.BaseDn, // The base dn to search
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf(lc.AuthFilter, user), // The filter to apply
|
||||
genLdapAttributeSearchList(), // A list attributes to retrieve
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ldap search fail: %v", err)
|
||||
}
|
||||
|
||||
if len(sr.Entries) == 0 {
|
||||
return nil, fmt.Errorf("cannot find such user: %v", user)
|
||||
}
|
||||
|
||||
if len(sr.Entries) > 1 {
|
||||
return nil, fmt.Errorf("multi users is search, query user: %v", user)
|
||||
}
|
||||
|
||||
if err := conn.Bind(sr.Entries[0].DN, pass); err != nil {
|
||||
return nil, fmt.Errorf("password error")
|
||||
}
|
||||
return sr, nil
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type LoginLog struct {
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Client string `json:"client"`
|
||||
Clock int64 `json:"clock"`
|
||||
Loginout string `json:"loginout"`
|
||||
}
|
||||
|
||||
func LoginLogNew(username, client, inout string) error {
|
||||
now := time.Now().Unix()
|
||||
obj := LoginLog{
|
||||
Username: username,
|
||||
Client: client,
|
||||
Clock: now,
|
||||
Loginout: inout,
|
||||
}
|
||||
_, err := DB["rdb"].Insert(obj)
|
||||
return err
|
||||
}
|
||||
|
||||
func LoginLogTotal(username string, btime, etime int64) (int64, error) {
|
||||
session := DB["rdb"].Where("clock between ? and ?", btime, etime)
|
||||
if username != "" {
|
||||
return session.Where("username like ?", username+"%").Count(new(LoginLog))
|
||||
}
|
||||
|
||||
return session.Count(new(LoginLog))
|
||||
}
|
||||
|
||||
func LoginLogGets(username string, btime, etime int64, limit, offset int) ([]LoginLog, error) {
|
||||
session := DB["rdb"].Where("clock between ? and ?", btime, etime).Limit(limit, offset).Desc("clock")
|
||||
if username != "" {
|
||||
session = session.Where("username like ?", username+"%")
|
||||
}
|
||||
|
||||
var objs []LoginLog
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
|
@ -0,0 +1,444 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/didi/nightingale/src/common/dataobj"
|
||||
"github.com/didi/nightingale/src/toolkits/stack"
|
||||
)
|
||||
|
||||
type AggrCalc struct {
|
||||
Id int64 `xorm:"id pk autoincr" json:"id"`
|
||||
Nid int64 `xorm:"nid" json:"nid"`
|
||||
Category int `xorm:"category" json:"category"`
|
||||
NewMetric string `xorm:"new_metric" json:"new_metric"`
|
||||
NewStep int `xorm:"new_step" json:"new_step"`
|
||||
GroupByString string `xorm:"groupby" json:"-"`
|
||||
RawMetricsString string `xorm:"raw_metrics" json:"-"`
|
||||
GlobalOperator string `xorm:"global_operator"json:"global_operator"` //指标聚合方式
|
||||
Expression string `xorm:"expression" json:"expression"`
|
||||
RPN string `xorm:"rpn" json:"rpn"` //用途?
|
||||
Status int `xorm:"status" json:"-"` //审核状态
|
||||
Quota int `xorm:"quota" json:"quota"` //用途?
|
||||
Comment string `xorm:"comment" json:"comment"`
|
||||
Creator string `xorm:"creator" json:"creator"`
|
||||
Created time.Time `xorm:"created" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"<-" json:"last_updated"`
|
||||
|
||||
RawMetrics []*dataobj.RawMetric `xorm:"-" json:"raw_metrics"`
|
||||
GroupBy []string `xorm:"-" json:"groupby"`
|
||||
VarNum int `xorm:"-" json:"var_num"`
|
||||
}
|
||||
|
||||
type AggrTagsFilter struct {
|
||||
TagK string `json:"tagk"`
|
||||
Opt string `json:"opt"`
|
||||
TagV []string `json:"tagv"`
|
||||
}
|
||||
|
||||
func (a *AggrCalc) Save() error {
|
||||
_, err := DB["mon"].InsertOne(a)
|
||||
return err
|
||||
}
|
||||
|
||||
func AggrCalcGet(where string, args ...interface{}) (*AggrCalc, error) {
|
||||
var obj AggrCalc
|
||||
has, err := DB["mon"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func AggrCalcsList(name string, nid int64) ([]*AggrCalc, error) {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
objs := make([]*AggrCalc, 0)
|
||||
|
||||
whereClause := "1 = 1"
|
||||
params := []interface{}{}
|
||||
|
||||
if name != "" {
|
||||
whereClause += " AND name LIKE ?"
|
||||
params = append(params, "%"+name+"%")
|
||||
}
|
||||
|
||||
if nid != 0 {
|
||||
whereClause += " AND nid = ?"
|
||||
params = append(params, nid)
|
||||
}
|
||||
|
||||
err := session.Where(whereClause, params...).Find(&objs)
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
stras := make([]*AggrCalc, 0)
|
||||
for _, obj := range objs {
|
||||
err = obj.Decode()
|
||||
if err != nil {
|
||||
return stras, err
|
||||
}
|
||||
stras = append(stras, obj)
|
||||
}
|
||||
return stras, err
|
||||
}
|
||||
|
||||
func (a *AggrCalc) Update(cols ...string) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
var obj AggrCalc
|
||||
exists, err := session.Id(a.Id).Get(&obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("%d not exists", a.Id)
|
||||
}
|
||||
|
||||
_, err = session.Id(a.Id).Cols(cols...).Update(a)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = saveHist(a.Id, "calc", "update", a.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func AggrCalcDel(id int64) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
var obj AggrCalc
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := session.Id(id).Get(&obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("%d not exists", obj.Id)
|
||||
}
|
||||
|
||||
if _, err := session.Id(id).Delete(new(AggrCalc)); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = saveHist(obj.Id, "calc", "delete", obj.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (a *AggrCalc) Encode() error {
|
||||
|
||||
groupByBytes, err := json.Marshal(a.GroupBy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode GroupBy err:%v", err)
|
||||
}
|
||||
a.GroupByString = string(groupByBytes)
|
||||
a.GlobalOperator = "none"
|
||||
|
||||
if !strings.HasPrefix(a.NewMetric, "aggr.") {
|
||||
return fmt.Errorf("新指标名必需以aggr.开头")
|
||||
}
|
||||
|
||||
if len(a.RawMetrics) > 100 {
|
||||
return fmt.Errorf("待聚合指标过多 > 100")
|
||||
}
|
||||
|
||||
for _, metric := range a.RawMetrics {
|
||||
if metric.Name == "" {
|
||||
return fmt.Errorf("待聚合指标名不能为空")
|
||||
}
|
||||
|
||||
if metric.VarID == "" {
|
||||
return fmt.Errorf("待聚合指标ID不能为空")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(metric.VarID, "$") && !strings.HasPrefix(metric.VarID, "#") {
|
||||
metric.VarID = "$" + metric.VarID
|
||||
}
|
||||
|
||||
// check operator
|
||||
if !isInList(metric.Opt, []string{"sum", "max", "avg", "min", "count"}) {
|
||||
return fmt.Errorf("聚合方法为空或不支持:" + metric.Opt)
|
||||
}
|
||||
|
||||
// check tag filter
|
||||
for _, filter := range metric.Filters {
|
||||
if filter.Opt != "=" && filter.Opt != "!=" {
|
||||
fmt.Errorf("过滤操作符无效")
|
||||
}
|
||||
|
||||
if filter.TagK == "" {
|
||||
fmt.Errorf("tagk不能为空")
|
||||
}
|
||||
for _, tagv := range filter.TagV {
|
||||
if tagv == "" {
|
||||
fmt.Errorf("tagv不能为空")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rawMetricsBytes, err := json.Marshal(a.RawMetrics)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode RawMetrics err:%v", err)
|
||||
}
|
||||
a.RawMetricsString = string(rawMetricsBytes)
|
||||
|
||||
// 把中缀表达式转化为后缀表达式,并check表达式合法性
|
||||
if a.Expression == "" { // 单指标聚合,没有expression,则默认为"$a"
|
||||
a.Expression = "$a"
|
||||
}
|
||||
checker := expChecker{
|
||||
state: stateNull,
|
||||
number: "",
|
||||
RPNs: make([]string, 0),
|
||||
}
|
||||
s := stack.New()
|
||||
|
||||
if len(a.Expression) > 100 {
|
||||
return fmt.Errorf("计算表达式不合法:表达式过长")
|
||||
}
|
||||
|
||||
for idx, c := range []rune("(" + a.Expression + ")") {
|
||||
ePrefix := "计算表达式不合法:第" + strconv.Itoa(idx) + "个字符:"
|
||||
switch {
|
||||
case unicode.IsSpace(c):
|
||||
continue // 忽略所有空白字符
|
||||
case c == '$':
|
||||
if !checker.toNext(stateDollar, c) {
|
||||
return fmt.Errorf(ePrefix + "$位置不合法")
|
||||
}
|
||||
case c == '#':
|
||||
if !checker.toNext(stateSharp, c) {
|
||||
return fmt.Errorf(ePrefix + "#位置不合法")
|
||||
}
|
||||
case c >= '0' && c <= '9':
|
||||
if !checker.toNext(stateNumber, c) {
|
||||
return fmt.Errorf(ePrefix + "数字位置不合法")
|
||||
}
|
||||
if len(checker.number) > 9 { // 常量不超过9位数
|
||||
return fmt.Errorf(ePrefix + "数字过长")
|
||||
}
|
||||
case c >= 'a' && c <= rune('a'+len(a.RawMetrics)-1):
|
||||
if !checker.toNext(stateLetter, c) {
|
||||
return fmt.Errorf(ePrefix + "变量位置不合法")
|
||||
}
|
||||
checker.append("$" + string(c))
|
||||
case c == '+' || c == '-' || c == '*' || c == '/':
|
||||
if !checker.toNext(stateMark, c) {
|
||||
return fmt.Errorf(ePrefix + "运算符号位置不合法")
|
||||
}
|
||||
for s.Len() > 0 {
|
||||
top := s.Peek().(string)
|
||||
if isLessPriority(top, string(c)) {
|
||||
s.Push(string(c))
|
||||
break
|
||||
}
|
||||
checker.append(top)
|
||||
s.Pop()
|
||||
}
|
||||
case c == '(':
|
||||
if !checker.toNext(stateLB, c) {
|
||||
return fmt.Errorf(ePrefix + "左括号位置不合法")
|
||||
}
|
||||
s.Push(string(c))
|
||||
case c == ')':
|
||||
if !checker.toNext(stateRB, c) {
|
||||
return fmt.Errorf(ePrefix + "右括号位置不合法")
|
||||
}
|
||||
found := false
|
||||
for s.Len() > 0 {
|
||||
top := s.Pop().(string)
|
||||
if top == "(" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
checker.append(top)
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf(ePrefix + "括号不匹配,请检查")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf(ePrefix + "不支持的字符")
|
||||
}
|
||||
}
|
||||
if s.Len() != 0 { // 已处理完,但符号栈没清空,说明左右括号不匹配
|
||||
return fmt.Errorf("计算表达式不合法:括号不匹配,请检查")
|
||||
}
|
||||
|
||||
a.RPN = checker.print()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AggrCalc) Decode() error {
|
||||
err := json.Unmarshal([]byte(a.GroupByString), &a.GroupBy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(a.RawMetricsString), &a.RawMetrics)
|
||||
return err
|
||||
}
|
||||
|
||||
/* expChecker 用于校验计算表达式的合法性 */
|
||||
const (
|
||||
stateNull = iota // 空状态
|
||||
stateLB // (
|
||||
stateRB // )
|
||||
stateNumber // 0-9
|
||||
stateDollar // $
|
||||
stateLetter // a-z
|
||||
stateMark // +-*/
|
||||
stateSharp // #
|
||||
)
|
||||
|
||||
type expChecker struct {
|
||||
state int
|
||||
number string
|
||||
isNumID bool
|
||||
RPNs []string
|
||||
}
|
||||
|
||||
func (e *expChecker) append(val string) {
|
||||
e.RPNs = append(e.RPNs, val)
|
||||
}
|
||||
func (e *expChecker) print() string {
|
||||
return strings.Join(e.RPNs, " ")
|
||||
}
|
||||
func (e *expChecker) toNext(targetState int, next rune) bool {
|
||||
// 检测状态转移是否合法,如果合法则转移至targetState
|
||||
valid := false
|
||||
switch e.state {
|
||||
case stateNull:
|
||||
valid = true
|
||||
case stateLB:
|
||||
switch targetState {
|
||||
case stateLB, stateDollar, stateSharp, stateNumber:
|
||||
valid = true
|
||||
}
|
||||
case stateRB:
|
||||
switch targetState {
|
||||
case stateRB, stateMark:
|
||||
valid = true
|
||||
}
|
||||
case stateLetter:
|
||||
switch targetState {
|
||||
case stateMark, stateRB:
|
||||
valid = true
|
||||
}
|
||||
case stateMark:
|
||||
switch targetState {
|
||||
case stateDollar, stateSharp, stateLB, stateNumber:
|
||||
valid = true
|
||||
}
|
||||
case stateDollar:
|
||||
switch targetState {
|
||||
case stateLetter:
|
||||
valid = true
|
||||
}
|
||||
case stateNumber:
|
||||
switch targetState {
|
||||
case stateNumber:
|
||||
valid = true
|
||||
case stateMark, stateRB:
|
||||
valid = true
|
||||
if e.isNumID {
|
||||
e.append("#" + e.number)
|
||||
} else {
|
||||
e.append(e.number)
|
||||
}
|
||||
e.isNumID = false
|
||||
e.number = ""
|
||||
}
|
||||
case stateSharp:
|
||||
switch targetState {
|
||||
case stateNumber:
|
||||
e.isNumID = true
|
||||
valid = true
|
||||
}
|
||||
}
|
||||
if valid {
|
||||
e.state = targetState
|
||||
if targetState == stateNumber {
|
||||
e.number += string(next)
|
||||
}
|
||||
}
|
||||
return valid
|
||||
}
|
||||
|
||||
/* helper func */
|
||||
func isInList(source string, validList []string) bool {
|
||||
for _, target := range validList {
|
||||
if source == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isLessPriority(a, b string) bool { // check 符号a的优先级 < 符号b (严格小于)
|
||||
if a == "(" {
|
||||
return true
|
||||
}
|
||||
if a == "+" || a == "-" {
|
||||
if b == "*" || b == "/" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package models
|
||||
|
||||
type Chart struct {
|
||||
Id int64 `json:"id"`
|
||||
SubclassId int64 `json:"subclass_id"`
|
||||
Configs string `json:"configs"`
|
||||
Weight int `json:"weight"`
|
||||
}
|
||||
|
||||
func (c *Chart) Add() error {
|
||||
_, err := DB["mon"].InsertOne(c)
|
||||
return err
|
||||
}
|
||||
|
||||
func ChartGets(subclassId int64) ([]Chart, error) {
|
||||
var objs []Chart
|
||||
err := DB["mon"].Where("subclass_id=?", subclassId).OrderBy("weight").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ChartGet(col string, val interface{}) (*Chart, error) {
|
||||
var obj Chart
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (c *Chart) Update(cols ...string) error {
|
||||
_, err := DB["mon"].Where("id=?", c.Id).Cols(cols...).Update(c)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Chart) Del() error {
|
||||
_, err := DB["mon"].Where("id=?", c.Id).Delete(new(Chart))
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,769 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type Collect struct {
|
||||
sync.RWMutex
|
||||
Ports map[int]*PortCollect `json:"ports"`
|
||||
Procs map[string]*ProcCollect `json:"procs"`
|
||||
Logs map[string]*LogCollect `json:"logs"`
|
||||
Plugins map[string]*PluginCollect `json:"plugins"`
|
||||
}
|
||||
|
||||
func NewCollect() *Collect {
|
||||
return &Collect{
|
||||
Ports: make(map[int]*PortCollect),
|
||||
Procs: make(map[string]*ProcCollect),
|
||||
Logs: make(map[string]*LogCollect),
|
||||
Plugins: make(map[string]*PluginCollect),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Collect) Update(cc *Collect) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
//更新端口采集配置
|
||||
c.Ports = make(map[int]*PortCollect)
|
||||
for k, v := range cc.Ports {
|
||||
c.Ports[k] = v
|
||||
}
|
||||
|
||||
//更新进程采集配置
|
||||
c.Procs = make(map[string]*ProcCollect)
|
||||
for k, v := range cc.Procs {
|
||||
c.Procs[k] = v
|
||||
}
|
||||
|
||||
//更新log采集配置
|
||||
c.Logs = make(map[string]*LogCollect)
|
||||
for k, v := range cc.Logs {
|
||||
c.Logs[k] = v
|
||||
}
|
||||
|
||||
//更新plugin采集配置
|
||||
c.Plugins = make(map[string]*PluginCollect)
|
||||
for k, v := range cc.Plugins {
|
||||
c.Plugins[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Collect) GetPorts() map[int]*PortCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[int]*PortCollect)
|
||||
for k, v := range c.Ports {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (c *Collect) GetProcs() map[string]*ProcCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[string]*ProcCollect)
|
||||
for k, v := range c.Procs {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (c *Collect) GetLogConfig() map[string]*LogCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[string]*LogCollect)
|
||||
for k, v := range c.Logs {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (c *Collect) GetPlugin() map[string]*PluginCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[string]*PluginCollect)
|
||||
for k, v := range c.Plugins {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
type PortCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
Tags string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
|
||||
Port int `json:"port"`
|
||||
Timeout int `json:"timeout"`
|
||||
}
|
||||
|
||||
type ProcCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
Tags string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
|
||||
Target string `json:"target"`
|
||||
CollectMethod string `json:"collect_method"`
|
||||
}
|
||||
|
||||
type PluginCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
Step int `json:"step"`
|
||||
FilePath string `json:"file_path"`
|
||||
Params string `json:"params"`
|
||||
Stdin string `json:"stdin"`
|
||||
Env string `json:"env"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
}
|
||||
|
||||
type LogCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
TagsStr string `xorm:"tags" json:"-"`
|
||||
Step int `json:"step"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
|
||||
Tags map[string]string `xorm:"-" json:"tags"`
|
||||
|
||||
FilePath string `json:"file_path"`
|
||||
TimeFormat string `json:"time_format"`
|
||||
Pattern string `json:"pattern"`
|
||||
Func string `json:"func"`
|
||||
FuncType string `json:"func_type"`
|
||||
Unit string `json:"unit"`
|
||||
|
||||
Degree int `json:"degree"`
|
||||
Zerofill int `xorm:"zero_fill" json:"zerofill"`
|
||||
Aggregate string `json:"aggregate"`
|
||||
|
||||
LocalUpdated int64 `xorm:"-" json:"-"`
|
||||
TimeReg *regexp.Regexp `xorm:"-" json:"-"`
|
||||
PatternReg *regexp.Regexp `xorm:"-" json:"-"`
|
||||
ExcludeReg *regexp.Regexp `xorm:"-" json:"-"`
|
||||
TagRegs map[string]*regexp.Regexp `xorm:"-" json:"-"`
|
||||
ParseSucc bool `xorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
type ApiCollectSid struct {
|
||||
Id int64 `json:"id"`
|
||||
Cid int64 `json:"cid"`
|
||||
Sid int64 `json:"sid"`
|
||||
}
|
||||
|
||||
type ApiCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
Domain string `json:"domain"`
|
||||
Path string `json:"path"`
|
||||
HeaderStr string `xorm:"header" json:"-"`
|
||||
Step int `json:"step"`
|
||||
Timeout int `json:"timeout"`
|
||||
Protocol string `json:"protocol"`
|
||||
PortStr string `xorm:"port" json:"-"`
|
||||
Method string `json:"method"`
|
||||
MaxRedirect int `json:"max_redirect"`
|
||||
PostBody string `json:"post_body"`
|
||||
ExpectedCodeStr string `xorm:"expected_code" json:"-"`
|
||||
ExpectedString string `json:"expected_string"`
|
||||
UnexpectedString string `json:"unexpected_string"`
|
||||
Region string `json:"region"`
|
||||
Comment string `json:"comment"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
|
||||
Header map[string]string `xorm:"-" json:"header"`
|
||||
ExpectedCode []string `xorm:"-" json:"expected_code"`
|
||||
Port int `xorm:"-" json:"port"`
|
||||
}
|
||||
|
||||
type Index struct {
|
||||
TagKey string `json:"tagKey"`
|
||||
Type string `json:"type"`
|
||||
Oid string `json:"oid"`
|
||||
Lookups []*Lookup `json:"lookups"`
|
||||
}
|
||||
|
||||
type Lookup struct {
|
||||
Labels []string `yaml:"labels" json:"labels"`
|
||||
Labelname string `yaml:"labelname" json:"labelname"`
|
||||
Oid string `yaml:"oid" json:"oid,omitempty"`
|
||||
Type string `yaml:"type" json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type SnmpCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
OidType int `json:"oid_type"` //1 通用指标 2 私有指标 3 自定义指标
|
||||
Module string `json:"module"`
|
||||
Metric string `json:"metric"`
|
||||
MetricType string `json:"metric_type"`
|
||||
Oid string `json:"oid"`
|
||||
Step int `json:"step"`
|
||||
Timeout int `json:"timeout"`
|
||||
Port int `json:"port"`
|
||||
IndexesStr string `xorm:"indexes" json:"-"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
|
||||
Indexes []*Index `xorm:"-" json:"indexes"`
|
||||
Region string `xorm:"-" json:"region"`
|
||||
Version string `xorm:"-" json:"version"`
|
||||
Auth string `xorm:"-" json:"auth"`
|
||||
}
|
||||
|
||||
// Secret is a string that must not be revealed on marshaling.
|
||||
type Secret string
|
||||
|
||||
type Auth struct {
|
||||
Community Secret `json:"community,omitempty"`
|
||||
SecurityLevel string `json:"security_level,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password Secret `json:"password,omitempty"`
|
||||
AuthProtocol string `json:"auth_protocol,omitempty"`
|
||||
PrivProtocol string `json:"priv_protocol,omitempty"`
|
||||
PrivPassword Secret `json:"priv_password,omitempty"`
|
||||
ContextName string `json:"context_name,omitempty"`
|
||||
}
|
||||
|
||||
type CollectHist struct {
|
||||
Id int64 `json:"id"`
|
||||
Cid int64 `json:"cid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Action string `json:"action"`
|
||||
Body string `json:"body"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"created" json:"created"`
|
||||
}
|
||||
|
||||
func GetPortCollects() ([]*PortCollect, error) {
|
||||
collects := []*PortCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (p *PortCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Id(p.Id).AllCols().Update(p); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
portByte, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(p.Id, "port", "update", p.Creator, string(portByte), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetProcCollects() ([]*ProcCollect, error) {
|
||||
collects := []*ProcCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (p *ProcCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Id(p.Id).AllCols().Update(p); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(p.Id, "port", "update", p.Creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetLogCollects() ([]*LogCollect, error) {
|
||||
collects := []*LogCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (p *LogCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Id(p.Id).AllCols().Update(p); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(p.Id, "log", "update", p.Creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (l *LogCollect) Encode() error {
|
||||
tags, err := json.Marshal(l.Tags)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode excl_nid err:%v", err)
|
||||
}
|
||||
|
||||
l.TagsStr = string(tags)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LogCollect) Decode() error {
|
||||
var err error
|
||||
|
||||
err = json.Unmarshal([]byte(l.TagsStr), &l.Tags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPluginCollects() ([]*PluginCollect, error) {
|
||||
collects := []*PluginCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (p *PluginCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Id(p.Id).AllCols().Update(p); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(p.Id, "plugin", "update", p.Creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetApiCollects() ([]*ApiCollect, error) {
|
||||
collects := []*ApiCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (a *ApiCollect) Encode() error {
|
||||
header, err := json.Marshal(a.Header)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode header err:%v", err)
|
||||
}
|
||||
a.HeaderStr = string(header)
|
||||
|
||||
expectedCode, err := json.Marshal(a.ExpectedCode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode expectedCode err:%v", err)
|
||||
}
|
||||
a.ExpectedCodeStr = string(expectedCode)
|
||||
|
||||
a.PortStr = strconv.Itoa(a.Port)
|
||||
|
||||
if a.Region == "" {
|
||||
a.Region = "default"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ApiCollect) Decode() error {
|
||||
err := json.Unmarshal([]byte(a.HeaderStr), &a.Header)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode header err:%v", err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(a.ExpectedCodeStr), &a.ExpectedCode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode ExpectedCodeStr err:%v", err)
|
||||
}
|
||||
|
||||
a.Port, err = strconv.Atoi(a.PortStr)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *ApiCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Id(a.Id).AllCols().Update(a); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(a.Id, "api", "update", a.Creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteApiCollect(id int64) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
_, err := session.Where("id = ?", id).Delete(new(ApiCollect))
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
var relCidSid ApiCollectSid
|
||||
has, err := session.Where("cid = ?", id).Get(&relCidSid)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
if has {
|
||||
err = StraDel(relCidSid.Sid)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func GetSidByCid(cid int64) (int64, error) {
|
||||
var cidSid ApiCollectSid
|
||||
_, err := DB["mon"].Where("cid = ?", cid).Get(&cidSid)
|
||||
return cidSid.Sid, err
|
||||
}
|
||||
|
||||
func (a *ApiCollectSid) Add() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
_, err := session.Where("cid = ?", a.Cid).Delete(new(ApiCollectSid))
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = session.Insert(a)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func CreateCollect(collectType, creator string, collect interface{}) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Insert(collect); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(collect)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(0, collectType, "create", creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func GetCollectByNid(collectType string, nids []int64) ([]interface{}, error) {
|
||||
var res []interface{}
|
||||
switch collectType {
|
||||
case "port":
|
||||
collects := []PortCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
case "proc":
|
||||
collects := []ProcCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
case "log":
|
||||
collects := []LogCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
c.Decode()
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
case "plugin":
|
||||
collects := []PluginCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("采集类型不合法")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GetCollectById(collectType string, cid int64) (interface{}, error) {
|
||||
switch collectType {
|
||||
case "port":
|
||||
collect := new(PortCollect)
|
||||
has, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
case "proc":
|
||||
collect := new(ProcCollect)
|
||||
has, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
case "log":
|
||||
collect := new(LogCollect)
|
||||
has, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
collect.Decode()
|
||||
return collect, err
|
||||
case "plugin":
|
||||
collect := new(PluginCollect)
|
||||
has, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("采集类型不合法")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func GetCollectByNameAndNid(collectType string, name string, nid int64) (interface{}, error) {
|
||||
switch collectType {
|
||||
case "port":
|
||||
collect := new(PortCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
case "proc":
|
||||
collect := new(ProcCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
case "log":
|
||||
collect := new(LogCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
collect.Decode()
|
||||
return collect, err
|
||||
case "plugin":
|
||||
collect := new(PluginCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("采集类型不合法")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func DeleteCollectById(collectType, creator string, cid int64) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
sql := "delete from " + collectType + "_collect where id = ?"
|
||||
_, err := DB["mon"].Exec(sql, cid)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(cid, collectType, "delete", creator, strconv.FormatInt(cid, 10), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func saveHist(id int64, tp string, action, username, body string, session *xorm.Session) error {
|
||||
h := CollectHist{
|
||||
Cid: id,
|
||||
CollectType: tp,
|
||||
Action: action,
|
||||
Creator: username,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
_, err := session.Insert(&h)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/monapi/config"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Id int64 `json:"id"`
|
||||
Sid int64 `json:"sid"`
|
||||
Sname string `json:"sname"`
|
||||
Nid int64 `json:"nid"`
|
||||
NodePath string `json:"node_path"`
|
||||
CurNodePath string `json:"cur_node_path"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Priority int `json:"priority"`
|
||||
EventType string `json:"event_type"` // alert|recovery
|
||||
Category int `json:"category"`
|
||||
Status uint16 `json:"status"`
|
||||
HashId uint64 `json:"hashid" xorm:"hashid"`
|
||||
Etime int64 `json:"etime"`
|
||||
Value string `json:"value"`
|
||||
Info string `json:"info"`
|
||||
Created time.Time `json:"created" xorm:"created"`
|
||||
Detail string `json:"detail"`
|
||||
Users string `json:"users"`
|
||||
Groups string `json:"groups"`
|
||||
Runbook string `json:"runbook"`
|
||||
NeedUpgrade int `json:"need_upgrade"`
|
||||
AlertUpgrade string `json:"alert_upgrade"`
|
||||
RecvUserIDs []int64 `json:"recv_user_ids" xorm:"-"`
|
||||
RealUpgrade bool `json:"real_upgrade" xorm:"-"`
|
||||
WorkGroups []int `json:"work_groups" xorm:"-"`
|
||||
CurNid string `json:"cur_nid"`
|
||||
}
|
||||
|
||||
type EventDetail struct {
|
||||
Metric string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Points []*EventDetailPoint `json:"points"`
|
||||
PredPoints []*EventDetailPoint `json:"pred_points,omitempty"` // 预测值, 预测值不为空时, 现场值对应的是实际值
|
||||
}
|
||||
|
||||
type EventDetailPoint struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Value float64 `json:"value"`
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
type EventAlertUpgrade struct {
|
||||
Users string `json:"users"`
|
||||
Groups string `json:"groups"`
|
||||
Duration int `json:"duration"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
|
||||
func ParseEtime(etime int64) string {
|
||||
t := time.Unix(etime, 0)
|
||||
return t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
type EventSlice []*Event
|
||||
|
||||
func (e EventSlice) Len() int {
|
||||
return len(e)
|
||||
}
|
||||
|
||||
func (e EventSlice) Less(i, j int) bool {
|
||||
return e[i].Etime < e[j].Etime
|
||||
}
|
||||
|
||||
func (e EventSlice) Swap(i, j int) {
|
||||
e[i], e[j] = e[j], e[i]
|
||||
}
|
||||
|
||||
func SaveEvent(event *Event) error {
|
||||
_, err := DB["mon"].Insert(event)
|
||||
return err
|
||||
}
|
||||
|
||||
func SaveEventStatus(id int64, status string) error {
|
||||
sql := "update event set status = status | ? where id = ?"
|
||||
_, err := DB["mon"].Exec(sql, GetStatus(status), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateEventPriority(id int64, priority int) error {
|
||||
sql := "update event set priority=? where id=?"
|
||||
_, err := DB["mon"].Exec(sql, priority, id)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Event) GetEventDetail() ([]EventDetail, error) {
|
||||
detail := []EventDetail{}
|
||||
|
||||
err := json.Unmarshal([]byte(e.Detail), &detail)
|
||||
return detail, err
|
||||
}
|
||||
|
||||
func EventTotal(stime, etime int64, nodePath, query, eventType string, priorities, sendTypes []string) (int64, error) {
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?)", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if eventType != "" {
|
||||
session = session.Where("event_type=?", eventType)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
total, err := session.Count(new(Event))
|
||||
return total, err
|
||||
}
|
||||
|
||||
func EventGets(stime, etime int64, nodePath, query, eventType string, priorities, sendTypes []string, limit, offset int) ([]Event, error) {
|
||||
var objs []Event
|
||||
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?)", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if eventType != "" {
|
||||
session = session.Where("event_type=?", eventType)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
err := session.Desc("etime").Limit(limit, offset).Find(&objs)
|
||||
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func EventGet(col string, value interface{}) (*Event, error) {
|
||||
var obj Event
|
||||
has, err := DB["mon"].Where(col+"=?", value).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func DelEventOlder(ts int64, batch int) error {
|
||||
sql := "delete from event where etime < ? limit ?"
|
||||
_, err := DB["mon"].Exec(sql, ts, batch)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func EventAlertUpgradeUnMarshal(str string) (EventAlertUpgrade, error) {
|
||||
var obj EventAlertUpgrade
|
||||
if strings.TrimSpace(str) == "" {
|
||||
return EventAlertUpgrade{
|
||||
Users: "[]",
|
||||
Groups: "[]",
|
||||
Duration: 0,
|
||||
Level: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(str), &obj)
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func EventCnt(hashid uint64, stime, etime string, isUpgrade bool) (int64, error) {
|
||||
session := DB["mon"].Where("hashid = ? and event_type = ? and created between ? and ?", hashid, config.ALERT, stime, etime)
|
||||
|
||||
if isUpgrade {
|
||||
return session.In("status", GetFlagsByStatus([]string{STATUS_UPGRADE, STATUS_SEND})).Count(new(Event))
|
||||
}
|
||||
|
||||
return session.In("status", GetFlagsByStatus([]string{STATUS_SEND})).Count(new(Event))
|
||||
}
|
||||
|
||||
func EventAlertUpgradeMarshal(alertUpgrade AlertUpgrade) (string, error) {
|
||||
eventAlertUpgrade := EventAlertUpgrade{
|
||||
Duration: alertUpgrade.Duration,
|
||||
Level: alertUpgrade.Level,
|
||||
}
|
||||
|
||||
if alertUpgrade.Users == nil {
|
||||
eventAlertUpgrade.Users = "[]"
|
||||
} else {
|
||||
upgradeUsers, err := json.Marshal(alertUpgrade.Users)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
eventAlertUpgrade.Users = string(upgradeUsers)
|
||||
}
|
||||
|
||||
if alertUpgrade.Groups == nil {
|
||||
eventAlertUpgrade.Groups = "[]"
|
||||
} else {
|
||||
upgradeGroups, err := json.Marshal(alertUpgrade.Groups)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
eventAlertUpgrade.Groups = string(upgradeGroups)
|
||||
}
|
||||
|
||||
alertUpgradebytes, err := json.Marshal(eventAlertUpgrade)
|
||||
|
||||
return string(alertUpgradebytes), err
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/slice"
|
||||
)
|
||||
|
||||
type EventCur struct {
|
||||
Id int64 `json:"id"`
|
||||
Sid int64 `json:"sid"`
|
||||
Sname string `json:"sname"`
|
||||
NodePath string `json:"node_path"`
|
||||
CurNodePath string `json:"cur_node_path"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Priority int `json:"priority"`
|
||||
EventType string `json:"event_type"` // alert|recovery
|
||||
Category int `json:"category"`
|
||||
Status uint16 `json:"status"`
|
||||
HashId uint64 `json:"hashid" xorm:"hashid"`
|
||||
Etime int64 `json:"etime"`
|
||||
Value string `json:"value"`
|
||||
Info string `json:"info"`
|
||||
Created time.Time `json:"created" xorm:"created"`
|
||||
Detail string `json:"detail"`
|
||||
Users string `json:"users"`
|
||||
Groups string `json:"groups"`
|
||||
Runbook string `json:"runbook"`
|
||||
Nid int64 `json:"nid"`
|
||||
IgnoreAlert int `json:"ignore_alert"`
|
||||
Claimants string `json:"claimants"`
|
||||
NeedUpgrade int `json:"need_upgrade"`
|
||||
AlertUpgrade string `json:"alert_upgrade"`
|
||||
CurNid string `json:"cur_nid"`
|
||||
WorkGroups []int `json:"work_groups" xorm:"-"`
|
||||
}
|
||||
|
||||
func UpdateEventCurPriority(hashid uint64, priority int) error {
|
||||
sql := "update event_cur set priority=? where hashid=?"
|
||||
_, err := DB["mon"].Exec(sql, priority, hashid)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func SaveEventCur(eventCur *EventCur) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has, err := session.Where("hashid=?", eventCur.HashId).Get(new(EventCur))
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if has {
|
||||
if _, err := session.Where("hashid=?", eventCur.HashId).Cols("sid", "sname", "node_path", "cur_node_path", "endpoint", "priority", "category", "status", "etime", "detail", "value", "info", "users", "groups", "runbook", "nid", "alert_upgrade", "need_upgrade", "endpoint_alias").Update(eventCur); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := session.Insert(eventCur); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateClaimantsById(userId, id int64) error {
|
||||
var obj EventCur
|
||||
has, err := DB["mon"].Where("id=?", id).Cols("claimants").Get(&obj)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return fmt.Errorf("event not exists")
|
||||
}
|
||||
|
||||
var users []int64
|
||||
if err = json.Unmarshal([]byte(obj.Claimants), &users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
users = append(users, userId)
|
||||
data, err := json.Marshal(slice.UniqueInt64(users))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Exec("update event_cur set claimants=? where id=?", string(data), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateClaimantsByNodePath(userId int64, nodePath string) error {
|
||||
var objs []EventCur
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := session.Where("node_path = ?", nodePath).Find(&objs); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(objs); i++ {
|
||||
var users []int64
|
||||
if err := json.Unmarshal([]byte(objs[i].Claimants), &users); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
users = append(users, userId)
|
||||
data, err := json.Marshal(slice.UniqueInt64(users))
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = session.Exec("update event_cur set claimants=? where id=?", string(data), objs[i].Id)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func EventCurDel(hashid uint64) error {
|
||||
_, err := DB["mon"].Where("hashid=?", hashid).Delete(new(EventCur))
|
||||
return err
|
||||
}
|
||||
|
||||
func SaveEventCurStatus(hashid uint64, status string) error {
|
||||
sql := "update event_cur set status = status | ? where hashid = ?"
|
||||
_, err := DB["mon"].Exec(sql, GetStatus(status), hashid)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func EventCurTotal(stime, etime int64, nodePath, query string, priorities, sendTypes []string) (int64, error) {
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?) and ignore_alert=0", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
total, err := session.Count(new(EventCur))
|
||||
return total, err
|
||||
}
|
||||
|
||||
func EventCurGets(stime, etime int64, nodePath, query string, priorities, sendTypes []string, limit, offset int) ([]EventCur, error) {
|
||||
var obj []EventCur
|
||||
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?) and ignore_alert=0", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ? ", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
err := session.Desc("etime").Limit(limit, offset).Find(&obj)
|
||||
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func EventCurGet(col string, value interface{}) (*EventCur, error) {
|
||||
var obj EventCur
|
||||
has, err := DB["mon"].Where(col+"=?", value).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (e *EventCur) EventIgnore() error {
|
||||
_, err := DB["mon"].Exec("delete from event_cur where id=?", e.Id)
|
||||
return err
|
||||
}
|
||||
|
||||
func DelEventCurOlder(ts int64, batch int) error {
|
||||
sql := "delete from event_cur where etime < ? limit ?"
|
||||
_, err := DB["mon"].Exec(sql, ts, batch)
|
||||
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
package models
|
||||
|
||||
// 0 0 0 0 0 0 处理中
|
||||
// 0 0 0 0 x 1 已发送
|
||||
// 0 0 0 0 1 x 已回调
|
||||
// 0 0 0 1 0 0 已屏蔽
|
||||
// 0 0 1 0 0 0 被收敛
|
||||
// 0 1 0 0 x 0 无接收人
|
||||
// 1 0 0 0 x 0 升级发送
|
||||
const (
|
||||
FLAG_SEND = iota
|
||||
FLAG_CALLBACK
|
||||
FLAG_MASK
|
||||
FLAG_CONVERGE
|
||||
FLAG_NONEUSER
|
||||
FLAG_UPGRADE
|
||||
)
|
||||
|
||||
const (
|
||||
STATUS_DOING = "doing" // 处理中
|
||||
STATUS_SEND = "send" // 已发送
|
||||
STATUS_NONEUSER = "none-user" // 无接收人
|
||||
STATUS_CALLBACK = "callback" // 已回调
|
||||
STATUS_MASK = "mask" // 已屏蔽
|
||||
STATUS_CONVERGE = "converge" // 频率限制
|
||||
STATUS_UPGRADE = "upgrade" // 升级报警
|
||||
)
|
||||
|
||||
func StatusConvert(s []string) []string {
|
||||
status := []string{}
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case STATUS_DOING:
|
||||
status = append(status, "处理中")
|
||||
case STATUS_SEND:
|
||||
status = append(status, "已发送")
|
||||
case STATUS_NONEUSER:
|
||||
status = append(status, "无接收人")
|
||||
case STATUS_CALLBACK:
|
||||
status = append(status, "已回调")
|
||||
case STATUS_MASK:
|
||||
status = append(status, "已屏蔽")
|
||||
case STATUS_CONVERGE:
|
||||
status = append(status, "已收敛")
|
||||
case STATUS_UPGRADE:
|
||||
status = append(status, "已升级")
|
||||
}
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func GetStatus(status string) int {
|
||||
switch status {
|
||||
case STATUS_SEND:
|
||||
return 1 << FLAG_SEND
|
||||
case STATUS_NONEUSER:
|
||||
return 1 << FLAG_NONEUSER
|
||||
case STATUS_CALLBACK:
|
||||
return 1 << FLAG_CALLBACK
|
||||
case STATUS_MASK:
|
||||
return 1 << FLAG_MASK
|
||||
case STATUS_CONVERGE:
|
||||
return 1 << FLAG_CONVERGE
|
||||
case STATUS_UPGRADE:
|
||||
return 1 << FLAG_UPGRADE
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetFlagsByStatus(ss []string) []uint16 {
|
||||
if len(ss) == 0 {
|
||||
return []uint16{}
|
||||
}
|
||||
|
||||
flags := make(map[string][]uint16)
|
||||
for _, s := range ss {
|
||||
switch s {
|
||||
case STATUS_DOING:
|
||||
flags[s] = getDoing()
|
||||
case STATUS_SEND:
|
||||
flags[s] = getSend()
|
||||
case STATUS_NONEUSER:
|
||||
flags[s] = getNoneUser()
|
||||
case STATUS_CALLBACK:
|
||||
flags[s] = getCallback()
|
||||
case STATUS_MASK:
|
||||
flags[s] = getMask()
|
||||
case STATUS_CONVERGE:
|
||||
flags[s] = getConverge()
|
||||
case STATUS_UPGRADE:
|
||||
flags[s] = getUpgrade()
|
||||
}
|
||||
}
|
||||
uss := make([][]uint16, 0)
|
||||
for _, s := range flags {
|
||||
uss = append(uss, s)
|
||||
}
|
||||
return interSection(uss)
|
||||
}
|
||||
|
||||
func GetStatusByFlag(flag uint16) []string {
|
||||
ret := make([]string, 0)
|
||||
|
||||
if flag == 0 {
|
||||
ret = append(ret, STATUS_DOING)
|
||||
return ret
|
||||
}
|
||||
|
||||
if (flag>>FLAG_UPGRADE)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_UPGRADE)
|
||||
}
|
||||
|
||||
if (flag>>FLAG_CONVERGE)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_CONVERGE)
|
||||
return ret
|
||||
}
|
||||
|
||||
if (flag>>FLAG_MASK)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_MASK)
|
||||
return ret
|
||||
}
|
||||
|
||||
if (flag>>FLAG_SEND)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_SEND)
|
||||
}
|
||||
|
||||
if (flag>>FLAG_CALLBACK)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_CALLBACK)
|
||||
}
|
||||
|
||||
if (flag>>FLAG_NONEUSER)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_NONEUSER)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// 0 0 0 0 0 0 正在处理
|
||||
func getDoing() []uint16 {
|
||||
return []uint16{0}
|
||||
}
|
||||
|
||||
// x 0 0 0 x 1 已发送
|
||||
func getSend() []uint16 {
|
||||
return []uint16{1, 3, 33, 35}
|
||||
}
|
||||
|
||||
// x 0 0 0 1 x 已回调
|
||||
func getCallback() []uint16 {
|
||||
return []uint16{2, 3, 34, 35}
|
||||
}
|
||||
|
||||
// 0 0 0 1 0 0 已屏蔽
|
||||
func getMask() []uint16 {
|
||||
return []uint16{4}
|
||||
}
|
||||
|
||||
// x 0 1 0 0 0 被收敛
|
||||
func getConverge() []uint16 {
|
||||
return []uint16{8, 40}
|
||||
}
|
||||
|
||||
// x 1 0 0 x 0 无接收人
|
||||
func getNoneUser() []uint16 {
|
||||
return []uint16{16, 18, 48, 50}
|
||||
}
|
||||
|
||||
// 1 x x 0 x x 已升级
|
||||
func getUpgrade() []uint16 {
|
||||
return []uint16{32, 33, 34, 35, 40, 41, 42, 43, 48, 49, 50, 51, 56, 57, 58, 59}
|
||||
}
|
||||
|
||||
func interSection(ss [][]uint16) []uint16 {
|
||||
if len(ss) == 0 {
|
||||
return []uint16{}
|
||||
}
|
||||
umap := make(map[uint16]int)
|
||||
for _, s := range ss {
|
||||
for _, su := range s {
|
||||
if _, found := umap[su]; found {
|
||||
umap[su] += 1
|
||||
} else {
|
||||
umap[su] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
ret := []uint16{}
|
||||
for su, cnt := range umap {
|
||||
if cnt == len(ss) {
|
||||
ret = append(ret, su)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type Instance struct {
|
||||
Id int64 `json:"id"`
|
||||
Module string `json:"module"`
|
||||
Identity string `json:"identity"` //ip 或者 机器名
|
||||
RPCPort string `json:"rpc_port" xorm:"rpc_port"`
|
||||
HTTPPort string `json:"http_port" xorm:"http_port"`
|
||||
TS int64 `json:"ts" xorm:"ts"`
|
||||
Remark string `json:"remark"`
|
||||
Active bool `xorm:"-" json:"active"`
|
||||
}
|
||||
|
||||
func (i *Instance) Add() error {
|
||||
_, err := DB["hbs"].InsertOne(i)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *Instance) Update() error {
|
||||
_, err := DB["hbs"].Where("id=?", i.Id).MustCols("ts", "http_port", "rpc_port").Update(i)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetInstanceBy(mod, identity, rpcPort, httpPort string) (*Instance, error) {
|
||||
var obj Instance
|
||||
has, err := DB["hbs"].Where("module=? and identity=? and rpc_port=? and http_port=?", mod, identity, rpcPort, httpPort).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func GetAllInstances(mod string, alive int) ([]*Instance, error) {
|
||||
objs := make([]*Instance, 0)
|
||||
var err error
|
||||
now := time.Now().Unix()
|
||||
|
||||
ts := now - 60
|
||||
if alive == 1 {
|
||||
err = DB["hbs"].Where("module = ? and ts > ?", mod, ts).OrderBy("id").Find(&objs)
|
||||
} else {
|
||||
err = DB["hbs"].Where("module = ?", mod).OrderBy("id").Find(&objs)
|
||||
}
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
for _, j := range objs {
|
||||
if j.TS > now-60 { //上报心跳时间在1分钟之内
|
||||
j.Active = true
|
||||
}
|
||||
}
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func DelById(id int64) error {
|
||||
_, err := DB["hbs"].Where("id=?", id).Delete(new(Instance))
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,384 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Maskconf struct {
|
||||
Id int64 `json:"id"`
|
||||
Category int `json:"category"`
|
||||
Nid int64 `json:"nid"`
|
||||
NodePath string `json:"node_path" xorm:"-"`
|
||||
Metric string `json:"metric"`
|
||||
Tags string `json:"tags"`
|
||||
Cause string `json:"cause"`
|
||||
User string `json:"user"`
|
||||
Btime int64 `json:"btime"`
|
||||
Etime int64 `json:"etime"`
|
||||
Endpoints []string `json:"endpoints" xorm:"-"`
|
||||
Nids []string `json:"nids" xorm:"-"`
|
||||
CurNidPaths map[string]string `json:"cur_nid_paths" xorm:"-"`
|
||||
}
|
||||
|
||||
type MaskconfEndpoints struct {
|
||||
Id int64 `json:"id"`
|
||||
MaskId int64 `json:"mask_id"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
}
|
||||
|
||||
type MaskconfNids struct {
|
||||
Id int64 `json:"id"`
|
||||
MaskId int64 `json:"mask_id"`
|
||||
Nid string `json:"nid"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
func (mc *Maskconf) AddEndpoints(endpoints []string) error {
|
||||
_, err := DB["mon"].Insert(mc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
affected := 0
|
||||
|
||||
for i := 0; i < len(endpoints); i++ {
|
||||
endpoint := strings.TrimSpace(endpoints[i])
|
||||
if endpoint == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Insert(&MaskconfEndpoints{
|
||||
MaskId: mc.Id,
|
||||
Endpoint: endpoint,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
affected++
|
||||
}
|
||||
|
||||
if affected == 0 {
|
||||
return fmt.Errorf("arg[endpoints] empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mc *Maskconf) AddNids(nidPaths map[string]string) error {
|
||||
_, err := DB["mon"].Insert(mc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
affected := 0
|
||||
for nid, path := range nidPaths {
|
||||
nid := strings.TrimSpace(nid)
|
||||
if nid == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Insert(&MaskconfNids{
|
||||
MaskId: mc.Id,
|
||||
Nid: nid,
|
||||
Path: path,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
affected++
|
||||
}
|
||||
|
||||
if affected == 0 {
|
||||
return fmt.Errorf("arg[nids] empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mc *Maskconf) FillEndpoints() error {
|
||||
var objs []MaskconfEndpoints
|
||||
err := DB["mon"].Where("mask_id=?", mc.Id).OrderBy("id").Find(&objs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt := len(objs)
|
||||
arr := make([]string, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
arr[i] = objs[i].Endpoint
|
||||
}
|
||||
|
||||
mc.Endpoints = arr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mc *Maskconf) FillNids() error {
|
||||
var objs []MaskconfNids
|
||||
err := DB["mon"].Where("mask_id=?", mc.Id).OrderBy("id").Find(&objs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt := len(objs)
|
||||
|
||||
mc.CurNidPaths = make(map[string]string, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
mc.CurNidPaths[objs[i].Nid] = objs[i].Path
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func MaskconfGets(nodeId int64) ([]Maskconf, error) {
|
||||
node, err := NodeGet("id=?", nodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if node.Leaf == 1 {
|
||||
var objs []Maskconf
|
||||
//找到nid关联的屏蔽配置
|
||||
err = DB["mon"].Where("nid=?", nodeId).OrderBy("id desc").Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(objs); i++ {
|
||||
objs[i].NodePath = node.Path
|
||||
}
|
||||
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
//找到屏蔽的node列表
|
||||
nodes, err := node.RelatedNodes() //可能有性能瓶颈
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count := len(nodes)
|
||||
if count == 0 {
|
||||
return []Maskconf{}, nil
|
||||
}
|
||||
|
||||
ids := make([]int64, 0, count)
|
||||
nmap := make(map[int64]Node, count)
|
||||
for i := 0; i < count; i++ {
|
||||
nmap[nodes[i].Id] = nodes[i]
|
||||
ids = append(ids, nodes[i].Id)
|
||||
}
|
||||
|
||||
var objs []Maskconf
|
||||
err = DB["mon"].In("nid", ids).Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count = len(objs)
|
||||
for i := 0; i < count; i++ {
|
||||
n, has := nmap[objs[i].Nid]
|
||||
if has {
|
||||
objs[i].NodePath = n.Path
|
||||
}
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return []Maskconf{}, nil
|
||||
}
|
||||
|
||||
sort.Slice(objs, func(i int, j int) bool {
|
||||
if objs[i].NodePath < objs[j].NodePath {
|
||||
return true
|
||||
}
|
||||
|
||||
if objs[i].Id > objs[j].Id {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
func MaskconfDel(id int64) error {
|
||||
_, err := DB["mon"].Where("mask_id=?", id).Delete(new(MaskconfEndpoints))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Where("mask_id=?", id).Delete(new(MaskconfNids))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Where("id=?", id).Delete(new(Maskconf))
|
||||
return err
|
||||
}
|
||||
|
||||
func MaskconfGetAll() ([]Maskconf, error) {
|
||||
var objs []Maskconf
|
||||
err := DB["mon"].Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func CleanExpireMask(now int64) error {
|
||||
var objs []Maskconf
|
||||
err := DB["mon"].Where("etime<?", now).Cols("id").Find(&objs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(objs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(objs); i++ {
|
||||
if _, err := session.Exec("delete from maskconf where id=?", objs[i].Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from maskconf_endpoints where mask_id=?", objs[i].Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from maskconf_nids where mask_id=?", objs[i].Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = session.Commit()
|
||||
return err
|
||||
}
|
||||
|
||||
func MaskconfGet(col string, value interface{}) (*Maskconf, error) {
|
||||
var obj Maskconf
|
||||
has, err := DB["mon"].Where(col+"=?", value).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (mc *Maskconf) UpdateEndpoints(endpoints []string, cols ...string) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Where("id=?", mc.Id).Cols(cols...).Update(mc); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from maskconf_endpoints where mask_id=?", mc.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
affected := 0
|
||||
for i := 0; i < len(endpoints); i++ {
|
||||
endpoint := strings.TrimSpace(endpoints[i])
|
||||
if endpoint == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := session.Insert(&MaskconfEndpoints{
|
||||
MaskId: mc.Id,
|
||||
Endpoint: endpoint,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
affected += 1
|
||||
}
|
||||
|
||||
if affected == 0 {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("arg[endpoints] empty")
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mc *Maskconf) UpdateNids(nidPaths map[string]string, cols ...string) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Where("id=?", mc.Id).Cols(cols...).Update(mc); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from maskconf_nids where mask_id=?", mc.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
affected := 0
|
||||
for nid, path := range nidPaths {
|
||||
nid := strings.TrimSpace(nid)
|
||||
if nid == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := session.Insert(&MaskconfNids{
|
||||
MaskId: mc.Id,
|
||||
Nid: nid,
|
||||
Path: path,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
affected++
|
||||
}
|
||||
|
||||
if affected == 0 {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("arg[endpoints] empty")
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Screen struct {
|
||||
Id int64 `json:"id"`
|
||||
NodeId int64 `json:"node_id"`
|
||||
Name string `json:"name"`
|
||||
LastUpdator string `json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"<-" json:"last_updated"`
|
||||
|
||||
NodePath string `json:"node_path" xorm:"-"`
|
||||
}
|
||||
|
||||
func (s *Screen) Add() error {
|
||||
_, err := DB["mon"].Insert(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func ScreenGets(nodeId int64) ([]Screen, error) {
|
||||
var objs []Screen
|
||||
err := DB["mon"].Where("node_id=?", nodeId).OrderBy("name").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ScreenGet(col string, val interface{}) (*Screen, error) {
|
||||
var obj Screen
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (s *Screen) Update(cols ...string) error {
|
||||
_, err := DB["mon"].Where("id=?", s.Id).Cols(cols...).Update(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Screen) Del() error {
|
||||
subclasses, err := ScreenSubclassGets(s.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt := len(subclasses)
|
||||
for i := 0; i < cnt; i++ {
|
||||
err = subclasses[i].Del()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Where("id=? and node_id=?", s.Id, s.NodeId).Delete(new(Screen))
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package models
|
||||
|
||||
type ScreenSubclass struct {
|
||||
Id int64 `json:"id"`
|
||||
ScreenId int64 `json:"screen_id"`
|
||||
Name string `json:"name"`
|
||||
Weight int `json:"weight"`
|
||||
}
|
||||
|
||||
func (s *ScreenSubclass) Add() error {
|
||||
_, err := DB["mon"].Insert(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func ScreenSubclassGets(screenId int64) ([]ScreenSubclass, error) {
|
||||
var objs []ScreenSubclass
|
||||
err := DB["mon"].Where("screen_id=?", screenId).OrderBy("weight").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ScreenSubclassGet(col string, val interface{}) (*ScreenSubclass, error) {
|
||||
var obj ScreenSubclass
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (s *ScreenSubclass) Update(cols ...string) error {
|
||||
_, err := DB["mon"].Where("id=?", s.Id).Cols(cols...).Update(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ScreenSubclass) Del() error {
|
||||
_, err := DB["mon"].Where("subclass_id=?", s.Id).Delete(new(Chart))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Where("id=?", s.Id).Delete(new(ScreenSubclass))
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,562 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type Stra struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Category int `json:"category"` //机器,非机器
|
||||
Nid int64 `json:"nid"`
|
||||
ExclNidStr string `xorm:"excl_nid" json:"-"` //排除的叶子节点
|
||||
AlertDur int `json:"alert_dur"` //单位秒,持续异常10分钟则产生异常event
|
||||
RecoveryDur int `json:"recovery_dur"` //单位秒,持续正常2分钟则产生恢复event,0表示立即产生恢复event
|
||||
RecoveryNotify int `json:"recovery_notify"` //0 发送恢复通知 1不发送恢复通知
|
||||
ExprsStr string `xorm:"exprs" json:"-"` //多个条件的监控实例需要相同,并且同时满足才产生event
|
||||
TagsStr string `xorm:"tags" json:"-"` //tag过滤条件
|
||||
EnableStime string `json:"enable_stime"` //策略生效开始时间
|
||||
EnableEtime string `json:"enable_etime"` //策略生效终止时间 支持23:00-02:00
|
||||
EnableDaysOfWeekStr string `xorm:"enable_days_of_week" json:"-"` //策略生效日期
|
||||
ConvergeStr string `xorm:"converge" json:"-"` //告警通知收敛,第1个值表示收敛周期,单位秒,第2个值表示周期内允许发送告警次数
|
||||
Priority int `json:"priority"`
|
||||
Callback string `json:"callback"`
|
||||
NotifyGroupStr string `xorm:"notify_group" json:"-"`
|
||||
NotifyUserStr string `xorm:"notify_user" json:"-"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"created" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"<-" json:"last_updated"`
|
||||
NeedUpgrade int `xorm:"need_upgrade" json:"need_upgrade"`
|
||||
AlertUpgradeStr string `xorm:"alert_upgrade" json:"-"`
|
||||
WorkGroupsStr string `xorm:"work_groups" json:"-"`
|
||||
Runbook string `xorm:"runbook" json:"runbook"`
|
||||
|
||||
ExclNid []int64 `xorm:"-" json:"excl_nid"`
|
||||
Nids []string `xorm:"-" json:"nids"`
|
||||
Exprs []Exp `xorm:"-" json:"exprs"`
|
||||
Tags []Tag `xorm:"-" json:"tags"`
|
||||
EnableDaysOfWeek []int `xorm:"-" json:"enable_days_of_week"`
|
||||
Converge []int `xorm:"-" json:"converge"`
|
||||
NotifyGroup []int `xorm:"-" json:"notify_group"`
|
||||
NotifyUser []int `xorm:"-" json:"notify_user"`
|
||||
LeafNids []int64 `xorm:"-" json:"leaf_nids"` //叶子节点id
|
||||
Endpoints []string `xorm:"-" json:"endpoints"`
|
||||
AlertUpgrade AlertUpgrade `xorm:"-" json:"alert_upgrade"`
|
||||
JudgeInstance string `xorm:"-" json:"judge_instance"`
|
||||
WorkGroups []int `xorm:"-" json:"work_groups"`
|
||||
}
|
||||
|
||||
func (s *Stra) GetMetric() string {
|
||||
for _, e := range s.Exprs {
|
||||
return e.Metric
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StraLog struct {
|
||||
Id int64 `json:"id"`
|
||||
Sid int64 `json:"sid"`
|
||||
Action string `json:"action"` // update|delete
|
||||
Body string `json:"body"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `json:"created" xorm:"created"`
|
||||
}
|
||||
|
||||
type Exp struct {
|
||||
Eopt string `json:"eopt"`
|
||||
Func string `json:"func"` //all,max,min
|
||||
Metric string `json:"metric"` //metric
|
||||
Params []int `json:"params"` //连续n秒
|
||||
Threshold float64 `json:"threshold"` //阈值
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Tkey string `json:"tkey"`
|
||||
Topt string `json:"topt"`
|
||||
Tval []string `json:"tval"` //修改为数组
|
||||
}
|
||||
|
||||
type AlertUpgrade struct {
|
||||
Users []int64 `json:"users"`
|
||||
Groups []int64 `json:"groups"`
|
||||
Duration int `json:"duration"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
|
||||
var MathOperators = map[string]bool{
|
||||
">": true,
|
||||
"<": true,
|
||||
">=": true,
|
||||
"<=": true,
|
||||
"!=": true,
|
||||
"=": true,
|
||||
}
|
||||
|
||||
func (s *Stra) Save() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = session.Insert(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = SaveStraCommit(s.Id, "add", s.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
session.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) Update() error {
|
||||
var obj Stra
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := session.Id(s.Id).Get(&obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("%d not exists", s.Id)
|
||||
}
|
||||
|
||||
_, err = session.Id(s.Id).AllCols().Update(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = SaveStraCommit(s.Id, "update", s.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
session.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func StraGet(col string, val interface{}) (*Stra, error) {
|
||||
var obj Stra
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func StraDel(id int64) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
var obj Stra
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := session.Id(id).Get(&obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("%d not exists", obj.Id)
|
||||
}
|
||||
|
||||
if _, err := session.Id(id).Delete(new(Stra)); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = SaveStraCommit(obj.Id, "delete", obj.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func StrasList(name string, priority int, nid int64) ([]*Stra, error) {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
objs := make([]*Stra, 0)
|
||||
|
||||
whereClause := "1 = 1"
|
||||
params := []interface{}{}
|
||||
|
||||
if name != "" {
|
||||
whereClause += " AND name LIKE ?"
|
||||
params = append(params, "%"+name+"%")
|
||||
}
|
||||
|
||||
if priority <= 3 {
|
||||
whereClause += " AND priority = ?"
|
||||
params = append(params, priority)
|
||||
}
|
||||
|
||||
var err error
|
||||
if nid != 0 {
|
||||
err = session.Where(whereClause, params...).Where("nid=?", nid).Find(&objs)
|
||||
} else {
|
||||
err = session.Where(whereClause, params...).Find(&objs)
|
||||
}
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
stras := make([]*Stra, 0)
|
||||
for _, obj := range objs {
|
||||
err = obj.Decode()
|
||||
if err != nil {
|
||||
return stras, err
|
||||
}
|
||||
stras = append(stras, obj)
|
||||
}
|
||||
return stras, err
|
||||
}
|
||||
|
||||
func StrasAll() ([]*Stra, error) {
|
||||
objs := make([]*Stra, 0)
|
||||
|
||||
err := DB["mon"].Find(&objs)
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
stras := make([]*Stra, 0)
|
||||
for _, obj := range objs {
|
||||
err = obj.Decode()
|
||||
if err != nil {
|
||||
return stras, err
|
||||
}
|
||||
stras = append(stras, obj)
|
||||
}
|
||||
return stras, err
|
||||
}
|
||||
|
||||
func EffectiveStrasList() ([]*Stra, error) {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
objs := make([]*Stra, 0)
|
||||
t := time.Now()
|
||||
|
||||
now := t.Format("15:04")
|
||||
weekday := strconv.Itoa(int(t.Weekday()))
|
||||
|
||||
err := session.Where("((enable_stime <= ? and enable_etime >= ? or (enable_stime > enable_etime and !(enable_stime > ? and enable_etime < ?))) and enable_days_of_week like ?)", now, now, now, now, "%"+weekday+"%").Find(&objs)
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
stras := make([]*Stra, 0)
|
||||
for _, obj := range objs {
|
||||
err = obj.Decode()
|
||||
if err != nil {
|
||||
return stras, err
|
||||
}
|
||||
stras = append(stras, obj)
|
||||
}
|
||||
return stras, err
|
||||
}
|
||||
|
||||
func SaveStraCommit(id int64, action, username, body string, session *xorm.Session) error {
|
||||
strategyLog := StraLog{
|
||||
Sid: id,
|
||||
Action: action,
|
||||
Body: body,
|
||||
Creator: username,
|
||||
}
|
||||
|
||||
if _, err := session.Insert(&strategyLog); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) HasPermssion() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) Encode() error {
|
||||
alertUpgrade, err := AlertUpgradeMarshal(s.AlertUpgrade)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode alert_upgrade err:%v", err)
|
||||
}
|
||||
|
||||
if s.NeedUpgrade == 1 {
|
||||
if len(s.AlertUpgrade.Users) == 0 && len(s.AlertUpgrade.Groups) == 0 {
|
||||
return fmt.Errorf("alert upgrade: users and groups is blank")
|
||||
}
|
||||
}
|
||||
|
||||
s.AlertUpgradeStr = alertUpgrade
|
||||
|
||||
exclNid, err := json.Marshal(s.ExclNid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode excl_nid err:%v", err)
|
||||
}
|
||||
s.ExclNidStr = string(exclNid)
|
||||
|
||||
exprs, err := json.Marshal(s.Exprs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode exprs err:%v", err)
|
||||
}
|
||||
s.ExprsStr = string(exprs)
|
||||
|
||||
//校验exprs
|
||||
var exprsTmp []Exp
|
||||
err = json.Unmarshal(exprs, &exprsTmp)
|
||||
for _, exp := range exprsTmp {
|
||||
if _, found := MathOperators[exp.Eopt]; !found {
|
||||
return fmt.Errorf("unknown exp.eopt:%s", exp)
|
||||
}
|
||||
}
|
||||
|
||||
tags, err := json.Marshal(s.Tags)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode Tags err:%v", err)
|
||||
}
|
||||
s.TagsStr = string(tags)
|
||||
|
||||
workGroupsByte, err := json.Marshal(s.WorkGroups)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode work_group err:%v", err)
|
||||
}
|
||||
s.WorkGroupsStr = string(workGroupsByte)
|
||||
|
||||
//校验tags
|
||||
var tagsTmp []Tag
|
||||
err = json.Unmarshal(tags, &tagsTmp)
|
||||
for _, tag := range tagsTmp {
|
||||
if tag.Topt != "=" && tag.Topt != "!=" {
|
||||
return fmt.Errorf("unknown tag.topt")
|
||||
}
|
||||
}
|
||||
|
||||
//校验时间
|
||||
err = checkDurationString(s.EnableStime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unknown enable_stime: %s", s.EnableStime)
|
||||
}
|
||||
|
||||
err = checkDurationString(s.EnableEtime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unknown enable_etime: %s", s.EnableEtime)
|
||||
}
|
||||
|
||||
for _, day := range s.EnableDaysOfWeek {
|
||||
if day > 7 || day < 0 {
|
||||
return fmt.Errorf("illegal period_days_of_week %v", s.EnableDaysOfWeek)
|
||||
}
|
||||
}
|
||||
enableDaysOfWeek, err := json.Marshal(s.EnableDaysOfWeek)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode EnableDaysOfWeek err:%v", err)
|
||||
}
|
||||
s.EnableDaysOfWeekStr = string(enableDaysOfWeek)
|
||||
|
||||
//校验收敛配置
|
||||
if len(s.Converge) != 2 {
|
||||
return fmt.Errorf("illegal converge %v", s.Converge)
|
||||
}
|
||||
Converge, err := json.Marshal(s.Converge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.ConvergeStr = string(Converge)
|
||||
|
||||
notifyGroup, err := json.Marshal(s.NotifyGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.NotifyGroupStr = string(notifyGroup)
|
||||
|
||||
notifyUser, err := json.Marshal(s.NotifyUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.NotifyUserStr = string(notifyUser)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) Decode() error {
|
||||
var err error
|
||||
|
||||
s.AlertUpgrade, err = AlertUpgradeUnMarshal(s.AlertUpgradeStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.ExclNidStr), &s.ExclNid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.ExprsStr), &s.Exprs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.TagsStr), &s.Tags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.EnableDaysOfWeekStr), &s.EnableDaysOfWeek)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.ConvergeStr), &s.Converge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.NotifyUserStr), &s.NotifyUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.NotifyGroupStr), &s.NotifyGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.WorkGroupsStr != "" {
|
||||
err = json.Unmarshal([]byte(s.WorkGroupsStr), &s.WorkGroups)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 00:00-23:59
|
||||
func checkDurationString(str string) error {
|
||||
slice := strings.Split(str, ":")
|
||||
if len(slice) != 2 {
|
||||
return fmt.Errorf("illegal duration", str)
|
||||
}
|
||||
|
||||
hour, err := strconv.Atoi(slice[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("illegal duration", str)
|
||||
}
|
||||
if hour < 0 || hour > 23 {
|
||||
return fmt.Errorf("illegal duration", str)
|
||||
}
|
||||
minute, err := strconv.Atoi(slice[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("illegal duration", str)
|
||||
}
|
||||
if minute < 0 || minute > 59 {
|
||||
return fmt.Errorf("illegal duration", str)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func AlertUpgradeMarshal(alterUpgrade AlertUpgrade) (string, error) {
|
||||
dat := AlertUpgrade{
|
||||
Duration: alterUpgrade.Duration,
|
||||
Level: alterUpgrade.Level,
|
||||
}
|
||||
|
||||
if alterUpgrade.Duration == 0 {
|
||||
dat.Duration = 60
|
||||
}
|
||||
|
||||
if alterUpgrade.Level == 0 {
|
||||
dat.Level = 1
|
||||
}
|
||||
|
||||
if alterUpgrade.Groups == nil {
|
||||
dat.Groups = []int64{}
|
||||
} else {
|
||||
dat.Groups = alterUpgrade.Groups
|
||||
}
|
||||
|
||||
if alterUpgrade.Users == nil {
|
||||
dat.Users = []int64{}
|
||||
} else {
|
||||
dat.Users = alterUpgrade.Users
|
||||
}
|
||||
|
||||
data, err := json.Marshal(dat)
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
func AlertUpgradeUnMarshal(str string) (AlertUpgrade, error) {
|
||||
var obj AlertUpgrade
|
||||
if strings.TrimSpace(str) == "" {
|
||||
return AlertUpgrade{
|
||||
Users: []int64{},
|
||||
Groups: []int64{},
|
||||
Duration: 0,
|
||||
Level: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(str), &obj)
|
||||
return obj, err
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package models
|
||||
|
||||
type TmpChart struct {
|
||||
Id int64 `json:"id"`
|
||||
Configs string `json:"configs"`
|
||||
Creator string `json:"creator"`
|
||||
}
|
||||
|
||||
func (t *TmpChart) Add() error {
|
||||
_, err := DB["mon"].InsertOne(t)
|
||||
return err
|
||||
}
|
||||
|
||||
func TmpChartGet(col string, val interface{}) (*TmpChart, error) {
|
||||
var obj TmpChart
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/toolkits/pkg/file"
|
||||
"github.com/toolkits/pkg/runner"
|
||||
)
|
||||
|
||||
type MySQLConf struct {
|
||||
Addr string `yaml:"addr"`
|
||||
Max int `yaml:"max"`
|
||||
Idle int `yaml:"idle"`
|
||||
Debug bool `yaml:"debug"`
|
||||
}
|
||||
|
||||
var DB = map[string]*xorm.Engine{}
|
||||
|
||||
func InitMySQL(names ...string) {
|
||||
confdir := path.Join(runner.Cwd, "etc")
|
||||
|
||||
mysqlYml := path.Join(confdir, "mysql.local.yml")
|
||||
if !file.IsExist(mysqlYml) {
|
||||
mysqlYml = path.Join(confdir, "mysql.yml")
|
||||
}
|
||||
|
||||
confs := make(map[string]MySQLConf)
|
||||
err := file.ReadYaml(mysqlYml, &confs)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot read yml[%s]: %v", mysqlYml, err)
|
||||
}
|
||||
|
||||
count := len(names)
|
||||
for i := 0; i < count; i++ {
|
||||
conf, has := confs[names[i]]
|
||||
if !has {
|
||||
log.Fatalf("no such mysql conf: %s", names[i])
|
||||
}
|
||||
|
||||
db, err := xorm.NewEngine("mysql", conf.Addr)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot connect mysql[%s]: %v", conf.Addr, err)
|
||||
}
|
||||
|
||||
db.SetMaxIdleConns(conf.Idle)
|
||||
db.SetMaxOpenConns(conf.Max)
|
||||
db.SetConnMaxLifetime(time.Hour)
|
||||
db.ShowSQL(conf.Debug)
|
||||
db.Logger().SetLevel(core.LOG_INFO)
|
||||
|
||||
DB[names[i]] = db
|
||||
}
|
||||
}
|
|
@ -0,0 +1,660 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/slice"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
Id int64 `json:"id"`
|
||||
Pid int64 `json:"pid"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
Note string `json:"note"`
|
||||
Path string `json:"path"`
|
||||
Leaf int `json:"leaf"`
|
||||
Cate string `json:"cate"`
|
||||
IconColor string `json:"icon_color"`
|
||||
IconChar string `json:"icon_char"`
|
||||
Proxy int `json:"proxy"`
|
||||
Creator string `json:"creator"`
|
||||
LastUpdated time.Time `json:"last_updated" xorm:"<-"`
|
||||
Admins []User `json:"admins" xorm:"-"`
|
||||
}
|
||||
|
||||
func (n *Node) FilterMyChildren(nodes []Node) []Node {
|
||||
if len(nodes) == 0 {
|
||||
return []Node{}
|
||||
}
|
||||
|
||||
var children []Node
|
||||
var prefix = n.Path + "."
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
if strings.HasPrefix(nodes[i].Path, prefix) {
|
||||
children = append(children, nodes[i])
|
||||
}
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
func (n *Node) FillAdmins() error {
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(NodeAdmin)).Where("node_id=?", n.Id).Select("user_id").Find(&ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
admins, err := UserGetByIds(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(admins); i++ {
|
||||
admins[i].UUID = ""
|
||||
}
|
||||
|
||||
n.Admins = admins
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateIconColor(newColor, cate string) error {
|
||||
_, err := DB["rdb"].Exec("UPDATE node SET icon_color=? WHERE cate=?", newColor, cate)
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeGet(where string, args ...interface{}) (*Node, error) {
|
||||
var obj Node
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
// NodeGets 在所有节点范围查询,比如管理员看服务树,就需要load所有数据
|
||||
func NodeGets(where string, args ...interface{}) (nodes []Node, err error) {
|
||||
if where != "" {
|
||||
err = DB["rdb"].Where(where, args...).OrderBy("path").Find(&nodes)
|
||||
} else {
|
||||
err = DB["rdb"].OrderBy("path").Find(&nodes)
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func NodeByIds(ids []int64) ([]Node, error) {
|
||||
if len(ids) == 0 {
|
||||
return []Node{}, nil
|
||||
}
|
||||
|
||||
return NodeGets(fmt.Sprintf("id in (%s)", str.IdsString(ids)))
|
||||
}
|
||||
|
||||
func NodeByPaths(paths []string) ([]Node, error) {
|
||||
if paths == nil || len(paths) == 0 {
|
||||
return []Node{}, nil
|
||||
}
|
||||
|
||||
var nodes []Node
|
||||
err := DB["rdb"].In("path", paths).Find(&nodes)
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func NodeNew(objPtr *Node, adminIds []int64) error {
|
||||
node, err := NodeGet("path=?", objPtr.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if node != nil {
|
||||
return fmt.Errorf("node[%s] already exists", objPtr.Path)
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Insert(objPtr); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(adminIds); i++ {
|
||||
if err := NodeAdminNew(session, objPtr.Id, adminIds[i]); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
var protectedNodeIdents = []string{
|
||||
"mysql",
|
||||
"rds",
|
||||
"redis",
|
||||
"mongo",
|
||||
"mongodb",
|
||||
"pg",
|
||||
"postgresql",
|
||||
"postgres",
|
||||
"api",
|
||||
"es",
|
||||
"elasticsearch",
|
||||
"topic",
|
||||
"kvm",
|
||||
"dc2",
|
||||
"ec2",
|
||||
"vm",
|
||||
"host",
|
||||
"bms",
|
||||
"pod",
|
||||
"container",
|
||||
}
|
||||
|
||||
// CreateChild 返回创建的子节点
|
||||
func (n *Node) CreateChild(ident, name, note, cate, creator string, leaf, proxy int, adminIds []int64) (*Node, error) {
|
||||
if n.Leaf == 1 {
|
||||
return nil, fmt.Errorf("parent node is leaf, cannot create child")
|
||||
}
|
||||
|
||||
if cate == "tenant" {
|
||||
return nil, fmt.Errorf("tenant node should be root node only")
|
||||
}
|
||||
|
||||
if ident == "" {
|
||||
return nil, fmt.Errorf("ident is blank")
|
||||
}
|
||||
|
||||
if !str.IsMatch(ident, "^[a-zA-Z0-9\\-\\_]+$") {
|
||||
return nil, fmt.Errorf("ident invalid")
|
||||
}
|
||||
|
||||
if creator != "system" {
|
||||
// 人为创建的节点,有些保留名字不能使用,是为了给PaaS各个子系统注册资源所用
|
||||
if (n.Path == "inner" || n.Cate == "project") && slice.ContainsString(protectedNodeIdents, ident) {
|
||||
return nil, fmt.Errorf("ident: %s is reserved", ident)
|
||||
}
|
||||
}
|
||||
|
||||
// 对于项目节点比较特殊,ident要求全局唯一
|
||||
if cate == "project" {
|
||||
node, err := NodeGet("ident=? and cate=?", ident, "project")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node != nil {
|
||||
return nil, fmt.Errorf("project[%s] already exists", ident)
|
||||
}
|
||||
|
||||
if leaf == 1 {
|
||||
return nil, fmt.Errorf("project[%s] should not be leaf", ident)
|
||||
}
|
||||
}
|
||||
|
||||
nc, err := NodeCateGet("ident=?", cate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if nc == nil {
|
||||
return nil, fmt.Errorf("node-category[%s] not found", cate)
|
||||
}
|
||||
|
||||
path := n.Path + "." + ident
|
||||
node, err := NodeGet("path=?", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if node != nil {
|
||||
return nil, fmt.Errorf("node[%s] already exists", path)
|
||||
}
|
||||
|
||||
child := Node{
|
||||
Pid: n.Id,
|
||||
Ident: ident,
|
||||
Name: name,
|
||||
Path: path,
|
||||
Leaf: leaf,
|
||||
Cate: cate,
|
||||
IconColor: nc.IconColor,
|
||||
Proxy: proxy,
|
||||
Note: note,
|
||||
Creator: creator,
|
||||
}
|
||||
|
||||
child.IconChar = strings.ToUpper(cate[0:1])
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = session.Insert(&child); err != nil {
|
||||
session.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(adminIds); i++ {
|
||||
if err := NodeAdminNew(session, child.Id, adminIds[i]); err != nil {
|
||||
session.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = session.Commit()
|
||||
|
||||
return &child, err
|
||||
}
|
||||
|
||||
func (n *Node) Modify(name, cate, note string, adminIds []int64) error {
|
||||
nc, err := NodeCateGet("ident=?", cate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nc == nil {
|
||||
return fmt.Errorf("node-category[%s] not found", cate)
|
||||
}
|
||||
|
||||
n.Name = name
|
||||
n.Cate = cate
|
||||
n.IconChar = strings.ToUpper(cate[0:1])
|
||||
n.IconColor = nc.IconColor
|
||||
n.Note = note
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Where("id=?", n.Id).Cols("name", "cate", "icon_char", "icon_color", "note").Update(n); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = NodeClearAdmins(session, n.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(adminIds); i++ {
|
||||
if err := NodeAdminNew(session, n.Id, adminIds[i]); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (n *Node) Del() error {
|
||||
// inner 租户节点不允许删除
|
||||
if n.Path == InnerTenantIdent {
|
||||
return fmt.Errorf("cannot delete inner tenant")
|
||||
}
|
||||
|
||||
// 叶子节点下不能有机器
|
||||
if n.Leaf == 1 {
|
||||
cnt, err := DB["rdb"].Where("node_id=?", n.Id).Count(new(NodeResource))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("there are resources binding this node")
|
||||
}
|
||||
}
|
||||
|
||||
// 非叶子节点下不能有子节点
|
||||
if n.Leaf == 0 {
|
||||
cnt, err := DB["rdb"].Where("pid=?", n.Id).Count(new(Node))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("node[%s] has children node", n.Path)
|
||||
}
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM node WHERE id=?", n.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM node_admin WHERE node_id=?", n.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM node_role WHERE node_id=?", n.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 在垃圾桶保留一份,以防万一后面要找回,只有超管可以看到这个垃圾桶页面
|
||||
nt := NodeTrash{
|
||||
Id: n.Id,
|
||||
Pid: n.Pid,
|
||||
Ident: n.Ident,
|
||||
Name: n.Name,
|
||||
Note: n.Note,
|
||||
Path: n.Path,
|
||||
Leaf: n.Leaf,
|
||||
Cate: n.Cate,
|
||||
IconColor: n.IconColor,
|
||||
IconChar: n.IconChar,
|
||||
Proxy: n.Proxy,
|
||||
Creator: n.Creator,
|
||||
}
|
||||
|
||||
if _, err := session.Insert(&nt); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (n *Node) RoleTotal(username string) (int64, error) {
|
||||
session := DB["rdb"].Where("node_id = ? or node_id in (select id from node where path like ?)", n.Id, n.Path+".%")
|
||||
if username != "" {
|
||||
session = session.Where("username = ?", username)
|
||||
}
|
||||
return session.Count(new(NodeRole))
|
||||
}
|
||||
|
||||
func (n *Node) RoleList(username string, limit, offset int) ([]NodeRole, error) {
|
||||
sql := "select node_role.id id, node_role.node_id node_id, node_role.username username, node_role.role_id role_id, node.path node_path from node_role, node where node_role.node_id = node.id and (node.id = %d or node.path like '%s')"
|
||||
|
||||
sql = fmt.Sprintf(sql, n.Id, n.Path+".%")
|
||||
|
||||
if username != "" {
|
||||
sql += fmt.Sprintf(" and node_role.username = '%s'", username)
|
||||
}
|
||||
|
||||
sql += " order by node.path limit ? offset ?"
|
||||
|
||||
var objs []NodeRole
|
||||
err := DB["rdb"].SQL(sql, limit, offset).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func (n *Node) Tenant() string {
|
||||
return strings.Split(n.Path, ".")[0]
|
||||
}
|
||||
|
||||
// LeafIds 叶子节点的id
|
||||
func (n *Node) LeafIds() ([]int64, error) {
|
||||
if n.Leaf == 1 {
|
||||
return []int64{n.Id}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(Node)).Where("path like ? and leaf = 1", n.Path+".%").Select("id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// 根据一堆节点获取下面的叶子节点的ID列表
|
||||
func LeafIdsByNodes(nodes []Node) ([]int64, error) {
|
||||
count := len(nodes)
|
||||
if count == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
lidsMap := make(map[int64]struct{})
|
||||
for i := 0; i < count; i++ {
|
||||
lids, err := nodes[i].LeafIds()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for j := 0; j < len(lids); j++ {
|
||||
lidsMap[lids[j]] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
count = len(lidsMap)
|
||||
list := make([]int64, 0, count)
|
||||
for lid := range lidsMap {
|
||||
list = append(list, lid)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func NodeIdsByPaths(paths []string) ([]int64, error) {
|
||||
if len(paths) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table("node").In("path", paths).Select("id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func PermNodes(myNodes []Node) ([]Node, error) {
|
||||
var ret []Node
|
||||
|
||||
for i := 0; i < len(myNodes); i++ {
|
||||
objs, err := NodeByPaths(Paths(myNodes[i].Path))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, objs...)
|
||||
|
||||
if myNodes[i].Leaf == 0 {
|
||||
var nodes []Node
|
||||
err = DB["rdb"].Where("path like ?", myNodes[i].Path+".%").Find(&nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(nodes) > 0 {
|
||||
ret = append(ret, nodes...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cnt := len(ret)
|
||||
set := make(map[string]struct{}, cnt)
|
||||
lst := make([]Node, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
if _, has := set[ret[i].Path]; has {
|
||||
continue
|
||||
}
|
||||
|
||||
lst = append(lst, ret[i])
|
||||
set[ret[i].Path] = struct{}{}
|
||||
}
|
||||
|
||||
return lst, nil
|
||||
}
|
||||
|
||||
// Unbind 从某个服务树节点解挂机器
|
||||
func (n *Node) Unbind(resIds []int64) error {
|
||||
if n.Leaf != 1 {
|
||||
return fmt.Errorf("node[%s] not leaf", n.Path)
|
||||
}
|
||||
|
||||
if len(resIds) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(resIds); i++ {
|
||||
if err := NodeResourceUnbind(n.Id, resIds[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bind 把资源挂载到某个树节点
|
||||
func (n *Node) Bind(resIds []int64) error {
|
||||
if n.Leaf != 1 {
|
||||
return fmt.Errorf("node[%s] not leaf", n.Path)
|
||||
}
|
||||
|
||||
tenant := n.Tenant()
|
||||
|
||||
if tenant != InnerTenantIdent {
|
||||
// 所有机器必须属于这个租户才可以挂载到这个租户下的节点,唯独inner节点特殊,inner节点可以挂载其他租户的资源
|
||||
var notMine []Resource
|
||||
err := DB["rdb"].In("id", resIds).Where("tenant<>?", tenant).Find(¬Mine)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
size := len(notMine)
|
||||
if size > 0 {
|
||||
arr := make([]string, size)
|
||||
for i := 0; i < size; i++ {
|
||||
arr[i] = fmt.Sprintf("%s[%s]", notMine[i].Ident, notMine[i].Name)
|
||||
}
|
||||
return fmt.Errorf("%s dont belong to tenant[%s]", strings.Join(arr, ", "), tenant)
|
||||
}
|
||||
}
|
||||
|
||||
cnt := len(resIds)
|
||||
for i := 0; i < cnt; i++ {
|
||||
if err := NodeResourceBind(n.Id, resIds[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//todo 是否需要待确认
|
||||
func (n *Node) RelatedNodes() ([]Node, error) {
|
||||
var nodes []Node
|
||||
err := DB["rdb"].Table(new(Node)).Where("id="+fmt.Sprint(n.Id)+" or path like ?", n.Path+".%").Find(&nodes)
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func GetLeafNidsForMon(nid int64, exclNid []int64) ([]int64, error) {
|
||||
var nids []int64
|
||||
idsMap := make(map[int64]struct{})
|
||||
|
||||
node, err := NodeGet("id=?", nid)
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
nodeIds, err := node.LeafIds()
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
for _, id := range nodeIds {
|
||||
idsMap[id] = struct{}{}
|
||||
}
|
||||
|
||||
for _, id := range exclNid {
|
||||
node, err := NodeGet("id=?", id)
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
if node == nil {
|
||||
continue
|
||||
}
|
||||
if node.Leaf == 1 {
|
||||
delete(idsMap, id)
|
||||
} else {
|
||||
nodeIds, err := node.LeafIds()
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
for _, id := range nodeIds {
|
||||
delete(idsMap, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for id, _ := range idsMap {
|
||||
nids = append(nids, id)
|
||||
}
|
||||
|
||||
return nids, err
|
||||
}
|
||||
|
||||
func GetRelatedNidsForMon(nid int64, exclNid []int64) ([]int64, error) {
|
||||
var nids []int64
|
||||
idsMap := make(map[int64]struct{})
|
||||
|
||||
node, err := NodeGet("id=?", nid)
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
nodes, err := node.RelatedNodes()
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
idsMap[node.Id] = struct{}{}
|
||||
}
|
||||
|
||||
for _, id := range exclNid {
|
||||
node, err := NodeGet("id=?", id)
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
if node == nil {
|
||||
continue
|
||||
}
|
||||
if node.Leaf == 1 {
|
||||
delete(idsMap, id)
|
||||
} else {
|
||||
nodes, err := node.RelatedNodes()
|
||||
if err != nil {
|
||||
return nids, err
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
delete(idsMap, node.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for id, _ := range idsMap {
|
||||
nids = append(nids, id)
|
||||
}
|
||||
|
||||
return nids, err
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package models
|
||||
|
||||
import "xorm.io/xorm"
|
||||
|
||||
type NodeAdmin struct {
|
||||
NodeId int64
|
||||
UserId int64
|
||||
}
|
||||
|
||||
func NodeAdminNew(session *xorm.Session, nodeId, userId int64) error {
|
||||
has, err := NodeAdminExists(session, nodeId, userId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if has {
|
||||
return nil
|
||||
}
|
||||
|
||||
na := NodeAdmin{
|
||||
NodeId: nodeId,
|
||||
UserId: userId,
|
||||
}
|
||||
|
||||
_, err = session.Insert(&na)
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeAdminExists(session *xorm.Session, nodeId, userId int64) (bool, error) {
|
||||
num, err := session.Where("node_id=? and user_id=?", nodeId, userId).Count(new(NodeAdmin))
|
||||
return num > 0, err
|
||||
}
|
||||
|
||||
func NodeClearAdmins(session *xorm.Session, nodeId int64) error {
|
||||
_, err := session.Where("node_id=?", nodeId).Delete(new(NodeAdmin))
|
||||
return err
|
||||
}
|
||||
|
||||
func NodesAdminExists(nodeIds []int64, userId int64) (bool, error) {
|
||||
num, err := DB["rdb"].Where("user_id=?", userId).In("node_id", nodeIds).Count(new(NodeAdmin))
|
||||
return num > 0, err
|
||||
}
|
||||
|
||||
// NodeIdsIamAdmin 我是管理员的节点ID列表
|
||||
func NodeIdsIamAdmin(userId int64) ([]int64, error) {
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(NodeAdmin)).Where("user_id=?", userId).Select("node_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package models
|
||||
|
||||
import "fmt"
|
||||
|
||||
type NodeCate struct {
|
||||
Id int64 `json:"id"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
IconColor string `json:"icon_color"`
|
||||
Protected int `json:"protected"`
|
||||
}
|
||||
|
||||
func NodeCateNew(objPtr *NodeCate) error {
|
||||
cnt, err := DB["rdb"].Where("ident=?", objPtr.Ident).Count(new(NodeCate))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("%s already exists", objPtr.Ident)
|
||||
}
|
||||
|
||||
_, err = DB["rdb"].Insert(objPtr)
|
||||
return err
|
||||
}
|
||||
|
||||
func (nc *NodeCate) Update(cols ...string) error {
|
||||
_, err := DB["rdb"].Where("id=?", nc.Id).Cols(cols...).Update(nc)
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeCateGet(where string, args ...interface{}) (*NodeCate, error) {
|
||||
var obj NodeCate
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
// Del 删除NodeCate的时候无需去管node表,某些node的cate已经被删除了,也没什么大不了
|
||||
func (nc *NodeCate) Del() error {
|
||||
if nc.Protected == 1 {
|
||||
return fmt.Errorf("cannot delete protected node-category: " + nc.Ident)
|
||||
}
|
||||
_, err := DB["rdb"].Where("id=?", nc.Id).Delete(new(NodeCate))
|
||||
return err
|
||||
}
|
||||
|
||||
// NodeCateGets 条数非常少,全部返回
|
||||
func NodeCateGets() ([]NodeCate, error) {
|
||||
var objs []NodeCate
|
||||
err := DB["rdb"].OrderBy("ident").Find(&objs)
|
||||
return objs, err
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NodeCateField struct {
|
||||
Id int64 `json:"id"`
|
||||
Cate string `json:"cate"`
|
||||
FieldIdent string `json:"field_ident"`
|
||||
FieldName string `json:"field_name"`
|
||||
FieldType string `json:"field_type"`
|
||||
FieldRequired int `json:"field_required"`
|
||||
FieldExtra string `json:"field_extra"`
|
||||
LastUpdated time.Time `json:"last_updated" xorm:"<-"`
|
||||
}
|
||||
|
||||
func (ncf *NodeCateField) Validate() error {
|
||||
if len(ncf.FieldIdent) > 255 {
|
||||
return fmt.Errorf("field ident too long")
|
||||
}
|
||||
|
||||
if len(ncf.FieldName) > 255 {
|
||||
return fmt.Errorf("field name too long")
|
||||
}
|
||||
|
||||
if len(ncf.FieldExtra) > 2048 {
|
||||
return fmt.Errorf("field extra too long")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NodeCateFieldNew(objPtr *NodeCateField) error {
|
||||
if err := objPtr.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt, err := DB["rdb"].Where("cate=? and field_ident=?", objPtr.Cate, objPtr.FieldIdent).Count(new(NodeCateField))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("%s already exists", objPtr.FieldIdent)
|
||||
}
|
||||
|
||||
_, err = DB["rdb"].Insert(objPtr)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ncf *NodeCateField) Update(cols ...string) error {
|
||||
if err := ncf.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := DB["rdb"].Where("id=?", ncf.Id).Cols(cols...).Update(ncf)
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeCateFieldGet(where string, args ...interface{}) (*NodeCateField, error) {
|
||||
var obj NodeCateField
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (ncf *NodeCateField) Del() error {
|
||||
_, err := DB["rdb"].Where("id=?", ncf.Id).Delete(new(NodeCateField))
|
||||
return err
|
||||
}
|
||||
|
||||
// NodeCateFieldGets 条数非常少,全部返回
|
||||
func NodeCateFieldGets(where string, args ...interface{}) ([]NodeCateField, error) {
|
||||
var objs []NodeCateField
|
||||
err := DB["rdb"].Where(where, args...).OrderBy("field_ident").Find(&objs)
|
||||
return objs, err
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type NodeFieldValue struct {
|
||||
Id int64 `json:"id"`
|
||||
NodeId int64 `json:"node_id"`
|
||||
FieldIdent string `json:"field_ident"`
|
||||
FieldValue string `json:"field_value"`
|
||||
}
|
||||
|
||||
func (nfv *NodeFieldValue) Validate() error {
|
||||
if len(nfv.FieldValue) > 255 {
|
||||
return fmt.Errorf("field value too long")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeFieldValueGets 条数非常少,全部返回
|
||||
func NodeFieldValueGets(nodeId int64) ([]NodeFieldValue, error) {
|
||||
var objs []NodeFieldValue
|
||||
err := DB["rdb"].Where("node_id = ?", nodeId).OrderBy("field_ident").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func NodeFieldValuePuts(nodeId int64, objs []NodeFieldValue) error {
|
||||
count := len(objs)
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
num, err := session.Where("node_id = ? and field_ident = ?", nodeId, objs[i].FieldIdent).Count(new(NodeFieldValue))
|
||||
if err != nil {
|
||||
return fmt.Errorf("count node_field_value fail: %v", err)
|
||||
}
|
||||
|
||||
if num > 0 {
|
||||
_, err = session.Exec("UPDATE node_field_value SET field_value = ? WHERE node_id = ? and field_ident = ?", objs[i].FieldValue, nodeId, objs[i].FieldIdent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update node_field_value fail: %v", err)
|
||||
}
|
||||
} else {
|
||||
_, err = session.InsertOne(NodeFieldValue{
|
||||
NodeId: nodeId,
|
||||
FieldIdent: objs[i].FieldIdent,
|
||||
FieldValue: objs[i].FieldValue,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("insert node_field_value fail: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package models
|
||||
|
||||
import "fmt"
|
||||
|
||||
type NodeResource struct {
|
||||
NodeId int64
|
||||
ResId int64
|
||||
}
|
||||
|
||||
func NodeResourceUnbind(nid, rid int64) error {
|
||||
_, err := DB["rdb"].Where("node_id=? and res_id=?", nid, rid).Delete(new(NodeResource))
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeResourceUnbindByRids(rids []int64) error {
|
||||
_, err := DB["rdb"].In("res_id", rids).Delete(new(NodeResource))
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeResourceBind(nid, rid int64) error {
|
||||
// 判断是否已经存在绑定关系
|
||||
total, err := DB["rdb"].Where("node_id=? and res_id=?", nid, rid).Count(new(NodeResource))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if total > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断node是否真实存在
|
||||
n, err := NodeGet("id=?", nid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n == nil {
|
||||
return fmt.Errorf("node[id:%d] not found", nid)
|
||||
}
|
||||
|
||||
// 判断resource是否真实存在
|
||||
res, err := ResourceGet("id=?", rid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res == nil {
|
||||
return fmt.Errorf("resource[id:%d] not found", rid)
|
||||
}
|
||||
|
||||
// 绑定节点和资源
|
||||
_, err = DB["rdb"].Insert(&NodeResource{
|
||||
NodeId: nid,
|
||||
ResId: rid,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeIdsGetByResIds(rids []int64) ([]int64, error) {
|
||||
if len(rids) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(NodeResource)).In("res_id", rids).Select("node_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// ResIdsGetByNodeIds 根据叶子节点获取资源ID列表
|
||||
func ResIdsGetByNodeIds(nids []int64) ([]int64, error) {
|
||||
if len(nids) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(NodeResource)).In("node_id", nids).Select("res_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package models
|
||||
|
||||
import "fmt"
|
||||
|
||||
type NodeRole struct {
|
||||
Id int64 `json:"id"`
|
||||
NodeId int64 `json:"node_id"`
|
||||
Username string `json:"username"`
|
||||
RoleId int64 `json:"role_id"`
|
||||
NodePath string `xorm:"<- 'node_path'" json:"node_path"`
|
||||
RoleTxt string `xorm:"-" json:"role_txt"`
|
||||
}
|
||||
|
||||
func (nr *NodeRole) Save() error {
|
||||
cnt, err := DB["rdb"].Where("node_id=? and username=? and role_id=?", nr.NodeId, nr.Username, nr.RoleId).Count(new(NodeRole))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("user already has this role")
|
||||
}
|
||||
|
||||
_, err = DB["rdb"].Insert(nr)
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeRoleExists(nodeIds, roleIds []int64, username string) (bool, error) {
|
||||
num, err := DB["rdb"].In("node_id", nodeIds).In("role_id", roleIds).Where("username=?", username).Count(new(NodeRole))
|
||||
return num > 0, err
|
||||
}
|
||||
|
||||
func NodeRoleDel(nodeId, roleId int64, username string) error {
|
||||
_, err := DB["rdb"].Where("node_id=? and role_id=? and username=?", nodeId, roleId, username).Delete(new(NodeRole))
|
||||
return err
|
||||
}
|
||||
|
||||
// NodeIdsBindingUsername 某人在哪些节点配置过权限
|
||||
func NodeIdsBindingUsername(username string) ([]int64, error) {
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table("node_role").Where("username=?", username).Select("node_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// NodeIdsBindingUsernameWithRoles 我以某些角色的名义绑定在哪些节点
|
||||
func NodeIdsBindingUsernameWithRoles(username string, roleIds []int64) ([]int64, error) {
|
||||
if len(roleIds) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table("node_role").Where("username=?", username).In("role_id", roleIds).Select("node_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// NodeIdsBindingUsernameWithOp 我在哪些节点上有这个操作权限
|
||||
func NodeIdsBindingUsernameWithOp(username, op string) ([]int64, error) {
|
||||
roleIds, err := RoleIdsHasOp(op)
|
||||
if err != nil {
|
||||
return []int64{}, err
|
||||
}
|
||||
|
||||
return NodeIdsBindingUsernameWithRoles(username, roleIds)
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"github.com/toolkits/pkg/slice"
|
||||
)
|
||||
|
||||
func TreeUntilProjectsGetByUser(user *User) ([]Node, error) {
|
||||
ret, err := UserPermNodes(user)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
cnt := len(ret)
|
||||
all := make(map[string]Node, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
all[ret[i].Path] = ret[i]
|
||||
}
|
||||
|
||||
// 只取project(含)以上的部分
|
||||
var oks []Node
|
||||
|
||||
set := make(map[string]struct{})
|
||||
for i := 0; i < cnt; i++ {
|
||||
if ret[i].Cate == "project" {
|
||||
paths := Paths(ret[i].Path)
|
||||
for _, path := range paths {
|
||||
if _, has := set[path]; has {
|
||||
continue
|
||||
}
|
||||
|
||||
set[path] = struct{}{}
|
||||
oks = append(oks, all[path])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oks, err
|
||||
}
|
||||
|
||||
func UserPermNodes(me *User) ([]Node, error) {
|
||||
var ret []Node
|
||||
var err error
|
||||
|
||||
if me.IsRooter() {
|
||||
// 我是超管,自然可以看到整棵树
|
||||
ret, err = NodeGets("")
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// 我可能是某个节点的管理员,或者在某些节点有授权
|
||||
nids1, err := NodeIdsIamAdmin(me.Id)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
nids2, err := NodeIdsBindingUsername(me.Username)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// nodes 是直接与我相关的节点,要返回树的话,下面的子节点、上面的关联父祖节点都要返回
|
||||
nodes, err := NodeByIds(slice.MergeInt64(nids1, nids2))
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
ret, err = PermNodes(nodes)
|
||||
return ret, err
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NodeTrash struct {
|
||||
Id int64 `json:"id"`
|
||||
Pid int64 `json:"pid"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
Note string `json:"note"`
|
||||
Path string `json:"path"`
|
||||
Leaf int `json:"leaf"`
|
||||
Cate string `json:"cate"`
|
||||
IconColor string `json:"icon_color"`
|
||||
IconChar string `json:"icon_char"`
|
||||
Proxy int `json:"proxy"`
|
||||
Creator string `json:"creator"`
|
||||
LastUpdated time.Time `json:"last_updated" xorm:"<-"`
|
||||
}
|
||||
|
||||
func NodeTrashTotal(query string) (int64, error) {
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
return DB["rdb"].Where("path like ? or name like ?", q, q).Count(new(NodeTrash))
|
||||
}
|
||||
|
||||
return DB["rdb"].Count(new(NodeTrash))
|
||||
}
|
||||
|
||||
func NodeTrashGets(query string, limit, offset int) ([]NodeTrash, error) {
|
||||
session := DB["rdb"].OrderBy("path").Limit(limit, offset)
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("path like ? or name like ?", q, q)
|
||||
}
|
||||
|
||||
var objs []NodeTrash
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func NodeTrashGetByIds(ids []int64) ([]NodeTrash, error) {
|
||||
if len(ids) == 0 {
|
||||
return []NodeTrash{}, nil
|
||||
}
|
||||
|
||||
var objs []NodeTrash
|
||||
err := DB["rdb"].In("id", ids).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
// 从node_trash表回收部分node,前端一个一个操作,也可以同一层级同时操作
|
||||
// 之前的父节点可能已经挪动过,所以回收的时候要注意重新更新path信息
|
||||
func NodeTrashRecycle(ids []int64) error {
|
||||
nts, err := NodeTrashGetByIds(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := len(nts)
|
||||
if count == 0 {
|
||||
return fmt.Errorf("nodes not found, refresh and retry")
|
||||
}
|
||||
|
||||
nodes := make([]Node, 0, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
node := Node{
|
||||
Id: nts[i].Id,
|
||||
Pid: nts[i].Pid,
|
||||
Ident: nts[i].Ident,
|
||||
Name: nts[i].Name,
|
||||
Note: nts[i].Note,
|
||||
Leaf: nts[i].Leaf,
|
||||
Cate: nts[i].Cate,
|
||||
IconColor: nts[i].IconColor,
|
||||
IconChar: nts[i].IconChar,
|
||||
Proxy: nts[i].Proxy,
|
||||
Creator: nts[i].Creator,
|
||||
}
|
||||
|
||||
if node.Cate != "tenant" {
|
||||
// 判断这个节点的父节点是否存在
|
||||
parent, err := NodeGet("id=?", nts[i].Pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if parent == nil {
|
||||
return fmt.Errorf("parent node not found")
|
||||
}
|
||||
|
||||
node.Path = parent.Path + "." + nts[i].Ident
|
||||
} else {
|
||||
// 租户节点,自然是没有父节点的
|
||||
node.Path = nts[i].Path
|
||||
}
|
||||
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
if _, err = session.InsertOne(nodes[i]); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = session.In("id", ids).Delete(new(NodeTrash)); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OperationLog struct {
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Clock int64 `json:"clock"`
|
||||
ResCl string `json:"res_cl"`
|
||||
ResId string `json:"res_id"`
|
||||
Detail string `json:"detail"`
|
||||
}
|
||||
|
||||
func OperationLogNew(username, rescl string, resid interface{}, detail string) error {
|
||||
now := time.Now().Unix()
|
||||
obj := OperationLog{
|
||||
Username: username,
|
||||
Clock: now,
|
||||
ResCl: rescl,
|
||||
ResId: fmt.Sprint(resid),
|
||||
Detail: detail,
|
||||
}
|
||||
|
||||
_, err := DB["rdb"].Insert(obj)
|
||||
return err
|
||||
}
|
||||
|
||||
func OperationLogGetsByRes(rescl, resid string, btime, etime int64, limit, offset int) ([]OperationLog, error) {
|
||||
var objs []OperationLog
|
||||
err := DB["rdb"].Where("clock between ? and ? and rescl=? and resid=?", btime, etime, rescl, resid).Desc("clock").Limit(limit, offset).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func OperationLogTotalByRes(rescl, resid string, btime, etime int64) (int64, error) {
|
||||
return DB["rdb"].Where("clock between ? and ? and rescl=? and resid=?", btime, etime, rescl, resid).Count(new(OperationLog))
|
||||
}
|
||||
|
||||
func OperationLogQuery(query string, btime, etime int64, limit, offset int) ([]OperationLog, error) {
|
||||
session := DB["rdb"].Where("clock between ? and ?", btime, etime).Desc("clock").Limit(limit, offset)
|
||||
if query != "" {
|
||||
session = session.Where("detail like ?", "%"+query+"%")
|
||||
}
|
||||
var objs []OperationLog
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func OperationLogTotal(query string, btime, etime int64) (int64, error) {
|
||||
session := DB["rdb"].Where("clock between ? and ?", btime, etime)
|
||||
if query != "" {
|
||||
session = session.Where("detail like ?", "%"+query+"%")
|
||||
}
|
||||
|
||||
return session.Count(new(OperationLog))
|
||||
}
|
|
@ -0,0 +1,344 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Resource struct {
|
||||
Id int64 `json:"id"`
|
||||
UUID string `json:"uuid" xorm:"'uuid'"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
Labels string `json:"labels"`
|
||||
Note string `json:"note"`
|
||||
Extend string `json:"extend"`
|
||||
Cate string `json:"cate"`
|
||||
Tenant string `json:"tenant"`
|
||||
LastUpdated time.Time `json:"last_updated" xorm:"<-"`
|
||||
}
|
||||
|
||||
func (r *Resource) Update(cols ...string) error {
|
||||
_, err := DB["rdb"].Where("id=?", r.Id).Cols(cols...).Update(r)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Resource) Save() error {
|
||||
_, err := DB["rdb"].InsertOne(r)
|
||||
return err
|
||||
}
|
||||
|
||||
func ResourceIdsByUUIDs(uuids []string) ([]int64, error) {
|
||||
if len(uuids) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(Resource)).In("uuid", uuids).Select("id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func ResourceIdsByIdents(idents []string) ([]int64, error) {
|
||||
if len(idents) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(Resource)).In("ident", idents).Select("id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func ResourceIdentsByIds(ids []int64) ([]string, error) {
|
||||
if len(ids) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var idents []string
|
||||
err := DB["rdb"].Table(new(Resource)).In("id", ids).Select("ident").Find(&idents)
|
||||
return idents, err
|
||||
}
|
||||
|
||||
func ResourceGet(where string, args ...interface{}) (*Resource, error) {
|
||||
var obj Resource
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func ResourceGets(where string, args ...interface{}) ([]Resource, error) {
|
||||
var objs []Resource
|
||||
err := DB["rdb"].Where(where, args...).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ResourceSearch(batch, field string) ([]Resource, error) {
|
||||
arr := str.ParseLines(strings.Replace(batch, ",", "\n", -1))
|
||||
if len(arr) == 0 {
|
||||
return []Resource{}, nil
|
||||
}
|
||||
|
||||
var objs []Resource
|
||||
err := DB["rdb"].In(field, arr).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
type ResourceBinding struct {
|
||||
Id int64 `json:"id"`
|
||||
UUID string `json:"uuid"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
Nodes []Node `json:"nodes"`
|
||||
}
|
||||
|
||||
// ResourceBindings 资源与节点的绑定关系,一个资源对应多个节点
|
||||
func ResourceBindings(resIds []int64) ([]ResourceBinding, error) {
|
||||
if len(resIds) == 0 {
|
||||
return []ResourceBinding{}, nil
|
||||
}
|
||||
|
||||
var nrs []NodeResource
|
||||
err := DB["rdb"].In("res_id", resIds).Find(&nrs)
|
||||
if err != nil {
|
||||
return []ResourceBinding{}, err
|
||||
}
|
||||
|
||||
cnt := len(nrs)
|
||||
if cnt == 0 {
|
||||
return []ResourceBinding{}, nil
|
||||
}
|
||||
|
||||
r2n := make(map[int64][]int64)
|
||||
arr := make([]int64, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
arr = append(arr, nrs[i].ResId)
|
||||
r2n[nrs[i].ResId] = append(r2n[nrs[i].ResId], nrs[i].NodeId)
|
||||
}
|
||||
|
||||
var resources []Resource
|
||||
err = DB["rdb"].In("id", arr).Find(&resources)
|
||||
if err != nil {
|
||||
return []ResourceBinding{}, err
|
||||
}
|
||||
|
||||
cnt = len(resources)
|
||||
ret := make([]ResourceBinding, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
nodeIds := r2n[resources[i].Id]
|
||||
|
||||
b := ResourceBinding{
|
||||
Id: resources[i].Id,
|
||||
UUID: resources[i].UUID,
|
||||
Ident: resources[i].Ident,
|
||||
Name: resources[i].Name,
|
||||
}
|
||||
|
||||
if nodeIds == nil || len(nodeIds) == 0 {
|
||||
b.Nodes = []Node{}
|
||||
ret = append(ret, b)
|
||||
continue
|
||||
}
|
||||
|
||||
var nodes []Node
|
||||
err = DB["rdb"].In("id", nodeIds).Find(&nodes)
|
||||
if err != nil {
|
||||
return []ResourceBinding{}, err
|
||||
}
|
||||
|
||||
b.Nodes = nodes
|
||||
ret = append(ret, b)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ResourceBindingsForMon 告警消息里要看到资源挂载的节点信息
|
||||
func ResourceBindingsForMon(idents []string) ([]string, error) {
|
||||
ids, err := ResourceIdsByIdents(idents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bindings, err := ResourceBindings(ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count := len(bindings)
|
||||
if count == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var ret []string
|
||||
for i := 0; i < count; i++ {
|
||||
for j := 0; j < len(bindings[i].Nodes); j++ {
|
||||
ret = append(ret, bindings[i].Ident+" - "+bindings[i].Name+" - "+bindings[i].Nodes[j].Path)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func buildResWhere(tenant, query, batch, field string) *xorm.Session {
|
||||
session := DB["rdb"].Table(new(Resource))
|
||||
|
||||
if tenant != "" {
|
||||
session = session.Where("tenant=?", tenant)
|
||||
}
|
||||
|
||||
if batch == "" && query != "" {
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
q := "%" + arr[i] + "%"
|
||||
session = session.Where("cate = ? or uuid = ? or ident like ? or name like ? or note like ? or labels like ?", arr[i], arr[i], q, q, q, q)
|
||||
}
|
||||
}
|
||||
|
||||
if batch != "" {
|
||||
arr := str.ParseLines(strings.Replace(batch, ",", "\n", -1))
|
||||
if len(arr) > 0 {
|
||||
session = session.In(field, arr)
|
||||
}
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
func ResourceOrphanTotal(tenant, query, batch, field string) (int64, error) {
|
||||
session := buildResWhere(tenant, query, batch, field)
|
||||
return session.Where("id not in (select res_id from node_resource)").Count()
|
||||
}
|
||||
|
||||
func ResourceOrphanList(tenant, query, batch, field string, limit, offset int) ([]Resource, error) {
|
||||
session := buildResWhere(tenant, query, batch, field)
|
||||
var objs []Resource
|
||||
err := session.Where("id not in (select res_id from node_resource)").OrderBy("ident").Limit(limit, offset).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ResourceUnderNodeTotal(leafIds []int64, query, batch, field string) (int64, error) {
|
||||
session := buildResWhere("", query, batch, field)
|
||||
return session.Where("id in (select res_id from node_resource where node_id in (" + str.IdsString(leafIds) + "))").Count()
|
||||
}
|
||||
|
||||
func ResourceUnderNodeGets(leafIds []int64, query, batch, field string, limit, offset int) ([]Resource, error) {
|
||||
session := buildResWhere("", query, batch, field)
|
||||
|
||||
rids, err := ResIdsGetByNodeIds(leafIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var objs []Resource
|
||||
if len(rids) == 0 {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
err = session.Where("id in ("+str.IdsString(rids)+")").OrderBy("ident").Limit(limit, offset).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ResourceUnregister(uuids []string) error {
|
||||
if len(uuids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ids, err := ResourceIdsByUUIDs(uuids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = NodeResourceUnbindByRids(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["rdb"].In("id", ids).Delete(new(Resource))
|
||||
return err
|
||||
}
|
||||
|
||||
// ResourceRegister 资源分配给某个租户的时候调用
|
||||
func ResourceRegister(hosts []Host, tenant string) error {
|
||||
count := len(hosts)
|
||||
for i := 0; i < count; i++ {
|
||||
uuid := fmt.Sprintf("host-%d", hosts[i].Id)
|
||||
res, err := ResourceGet("uuid=?", uuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res == nil {
|
||||
res = &Resource{
|
||||
UUID: uuid,
|
||||
Ident: hosts[i].Ident,
|
||||
Name: hosts[i].Name,
|
||||
Cate: hosts[i].Cate,
|
||||
Tenant: tenant,
|
||||
}
|
||||
|
||||
// 如果host加个字段,并且要放到extend里,这里要改
|
||||
fields := map[string]interface{}{
|
||||
"cpu": hosts[i].CPU,
|
||||
"mem": hosts[i].Mem,
|
||||
"disk": hosts[i].Disk,
|
||||
}
|
||||
|
||||
js, err := json.Marshal(fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res.Extend = string(js)
|
||||
err = res.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if res.Tenant != "" && res.Tenant != tenant {
|
||||
// 之前有归属,如果归属发生变化,解除之前的挂载关系
|
||||
err = NodeResourceUnbindByRids([]int64{res.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
res.Ident = hosts[i].Ident
|
||||
res.Name = hosts[i].Name
|
||||
res.Cate = hosts[i].Cate
|
||||
res.Tenant = tenant
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"cpu": hosts[i].CPU,
|
||||
"mem": hosts[i].Mem,
|
||||
"disk": hosts[i].Disk,
|
||||
}
|
||||
|
||||
js, err := json.Marshal(fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res.Extend = string(js)
|
||||
err = res.Update("ident", "name", "cate", "extend", "tenant")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Role struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Note string `json:"note"`
|
||||
Cate string `json:"cate"`
|
||||
}
|
||||
|
||||
func (r *Role) CheckFields() error {
|
||||
if len(r.Name) > 32 {
|
||||
return fmt.Errorf("name too long")
|
||||
}
|
||||
|
||||
if len(r.Note) > 128 {
|
||||
return fmt.Errorf("note too long")
|
||||
}
|
||||
|
||||
if r.Cate != "global" && r.Cate != "local" {
|
||||
return fmt.Errorf("cate invalid")
|
||||
}
|
||||
|
||||
if str.Dangerous(r.Name) {
|
||||
return fmt.Errorf("name dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(r.Note) {
|
||||
return fmt.Errorf("note dangerous")
|
||||
}
|
||||
|
||||
if strings.ContainsAny(r.Name, ".%/") {
|
||||
return fmt.Errorf("name invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RoleGetByIds(ids []int64) (roles []Role, err error) {
|
||||
if len(ids) == 0 {
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
err = DB["rdb"].In("id", ids).OrderBy("name").Find(&roles)
|
||||
return roles, err
|
||||
}
|
||||
|
||||
func RoleFind(cate string) ([]Role, error) {
|
||||
var objs []Role
|
||||
|
||||
session := DB["rdb"].OrderBy("name")
|
||||
if cate != "" {
|
||||
session = session.Where("cate=?", cate)
|
||||
}
|
||||
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
// RoleMap key: role_id, value: role_name
|
||||
func RoleMap(cate string) (map[int64]string, error) {
|
||||
roles, err := RoleFind(cate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count := len(roles)
|
||||
m := make(map[int64]string, count)
|
||||
for i := 0; i < count; i++ {
|
||||
m[roles[i].Id] = roles[i].Name
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (r *Role) Save(ops []string) error {
|
||||
if err := r.CheckFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
cnt, err := session.Where("name=?", r.Name).Count(new(Role))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("role[%s] already exists", r.Name)
|
||||
}
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Insert(r); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(ops); i++ {
|
||||
if err = roleOpAdd(session, r.Id, ops[i]); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func roleOpAdd(session *xorm.Session, rid int64, op string) error {
|
||||
var link RoleOperation
|
||||
has, err := session.Where("role_id=? and operation=?", rid, op).Get(&link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if has {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = session.Insert(&RoleOperation{
|
||||
RoleId: rid,
|
||||
Operation: op,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func RoleGet(where string, args ...interface{}) (*Role, error) {
|
||||
var obj Role
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (r *Role) Modify(name, note, cate string, ops []string) error {
|
||||
if r.Name != name {
|
||||
cnt, err := DB["rdb"].Where("name = ? and id <> ?", name, r.Id).Count(new(Role))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("role[%s] already exists", name)
|
||||
}
|
||||
}
|
||||
|
||||
tolocal := false
|
||||
if r.Cate != cate && cate == "local" {
|
||||
tolocal = true
|
||||
}
|
||||
|
||||
r.Name = name
|
||||
r.Note = note
|
||||
r.Cate = cate
|
||||
|
||||
if err := r.CheckFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Where("id=?", r.Id).Cols("name", "note", "cate").Update(r); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if tolocal {
|
||||
// 原来作为全局角色绑定的人员,就没有用了
|
||||
if _, err := session.Exec("DELETE FROM role_global_user WHERE role_id=?", r.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM role_operation WHERE role_id=?", r.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(ops); i++ {
|
||||
if err := roleOpAdd(session, r.Id, ops[i]); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (r *Role) Del() error {
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM role_operation WHERE role_id=?", r.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM role_global_user WHERE role_id=?", r.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM node_role WHERE role_id=?", r.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM role WHERE id=?", r.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (r *Role) BindUsers(userIds []int64) error {
|
||||
ids, err := safeUserIds(userIds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
for i := 0; i < len(ids); i++ {
|
||||
cnt, err := session.Where("role_id=? and user_id=?", r.Id, ids[i]).Count(new(RoleGlobalUser))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = session.Insert(RoleGlobalUser{RoleId: r.Id, UserId: ids[i]})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Role) UnbindUsers(ids []int64) error {
|
||||
if ids == nil || len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := DB["rdb"].Where("role_id=?", r.Id).In("user_id", ids).Delete(new(RoleGlobalUser))
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Role) GlobalUserIds() ([]int64, error) {
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table("role_global_user").Where("role_id=?", r.Id).Select("user_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package models
|
||||
|
||||
type RoleGlobalUser struct {
|
||||
RoleId int64 `json:"role_id" xorm:"'role_id'"`
|
||||
UserId int64 `json:"user_id" xorm:"'user_id'"`
|
||||
}
|
||||
|
||||
// UserHasGlobalRole 查看某个用户是否有某个全局角色
|
||||
func UserHasGlobalRole(userId int64, roleIds []int64) (bool, error) {
|
||||
cnt, err := DB["rdb"].Where("user_id=?", userId).In("role_id", roleIds).Count(new(RoleGlobalUser))
|
||||
return cnt > 0, err
|
||||
}
|
||||
|
||||
func RoleIdsGetByUserId(userId int64) ([]int64, error) {
|
||||
var roleIds []int64
|
||||
err := DB["rdb"].Table(new(RoleGlobalUser)).Where("user_id=?", userId).Select("role_id").Find(&roleIds)
|
||||
return roleIds, err
|
||||
}
|
||||
|
||||
func UserIdsGetByRoleIds(roleIds []int64) ([]int64, error) {
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table(new(RoleGlobalUser)).In("role_id", roleIds).Select("user_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"github.com/toolkits/pkg/slice"
|
||||
)
|
||||
|
||||
type RoleOperation struct {
|
||||
Id int64 `json:"id"`
|
||||
RoleId int64 `json:"role_id"`
|
||||
Operation string `json:"operation"`
|
||||
}
|
||||
|
||||
func OperationsOfRoles(rids []int64) ([]string, error) {
|
||||
if len(rids) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var ops []string
|
||||
err := DB["rdb"].Table("role_operation").In("role_id", rids).Select("operation").Find(&ops)
|
||||
return ops, err
|
||||
}
|
||||
|
||||
// RoleIdsHasOp 看哪些role里边包含operation
|
||||
func RoleIdsHasOp(op string) ([]int64, error) {
|
||||
var ids []int64
|
||||
err := DB["rdb"].Table("role_operation").Where("operation=?", op).Select("role_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func RoleBiggerThan(roleid int64) ([]int64, error) {
|
||||
var objs []RoleOperation
|
||||
err := DB["rdb"].Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := make(map[int64][]string)
|
||||
count := len(objs)
|
||||
for i := 0; i < count; i++ {
|
||||
m[objs[i].RoleId] = append(m[objs[i].RoleId], objs[i].Operation)
|
||||
}
|
||||
|
||||
ret := []int64{}
|
||||
ops := m[roleid]
|
||||
|
||||
for rid := range m {
|
||||
if slice.ContainsSlice(ops, m[rid]) {
|
||||
ret = append(ret, rid)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TaskAction struct {
|
||||
Id int64
|
||||
Action string
|
||||
Clock int64
|
||||
}
|
||||
|
||||
func TaskActionGet(where string, args ...interface{}) (*TaskAction, error) {
|
||||
var obj TaskAction
|
||||
has, err := DB["job"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func TaskActionExistsIds(ids []int64) ([]int64, error) {
|
||||
if len(ids) == 0 {
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
var ret []int64
|
||||
err := DB["job"].Table("task_action").In("id", ids).Select("id").Find(&ret)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func CancelWaitingHosts(id int64) error {
|
||||
sql := fmt.Sprintf("UPDATE %s SET status = 'cancelled' WHERE id = %d and status = 'waiting'", tht(id), id)
|
||||
_, err := DB["job"].Exec(sql)
|
||||
return err
|
||||
}
|
||||
|
||||
func StartTask(id int64) error {
|
||||
_, err := DB["job"].Exec("UPDATE task_scheduler SET scheduler='' WHERE id=?", id)
|
||||
return err
|
||||
}
|
||||
|
||||
func CancelTask(id int64) error {
|
||||
return CancelWaitingHosts(id)
|
||||
}
|
||||
|
||||
func KillTask(id int64) error {
|
||||
if err := CancelWaitingHosts(id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("UPDATE task_host_doing SET clock=?, action='kill' WHERE id=? and action <> 'kill'", now, id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf("UPDATE %s SET status = 'killing' WHERE id=%d and status='running'", tht(id), id)
|
||||
|
||||
if _, err := session.Exec(sql); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (a *TaskAction) Update(action string) error {
|
||||
if !(action == "start" || action == "cancel" || action == "kill" || action == "pause") {
|
||||
return fmt.Errorf("action invalid")
|
||||
}
|
||||
|
||||
a.Action = action
|
||||
a.Clock = time.Now().Unix()
|
||||
_, err := DB["job"].Where("id=?", a.Id).Cols("action", "clock").Update(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if action == "start" {
|
||||
return StartTask(a.Id)
|
||||
}
|
||||
|
||||
if action == "cancel" {
|
||||
return CancelTask(a.Id)
|
||||
}
|
||||
|
||||
if action == "kill" {
|
||||
return KillTask(a.Id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LongTaskIds two weeks ago
|
||||
func LongTaskIds() ([]int64, error) {
|
||||
clock := time.Now().Unix() - 604800*2
|
||||
var ids []int64
|
||||
err := DB["job"].Table("task_action").Where("clock < ?", clock).Select("id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TaskHost struct {
|
||||
Id int64 `json:"id"`
|
||||
Host string `json:"host"`
|
||||
Status string `json:"status"`
|
||||
Stdout string `json:"stdout"`
|
||||
Stderr string `json:"stderr"`
|
||||
}
|
||||
|
||||
func tht(id int64) string {
|
||||
return fmt.Sprintf("task_host_%d", id%100)
|
||||
}
|
||||
|
||||
func TaskHostGet(id int64, host string) (*TaskHost, error) {
|
||||
var obj TaskHost
|
||||
has, err := DB["job"].Table(tht(id)).Where("id=? and host=?", id, host).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func MarkDoneStatus(id, clock int64, host, status, stdout, stderr string) error {
|
||||
count, err := DoingHostCount("id=? and host=? and clock=?", id, host, clock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf("UPDATE %s SET status=?, stdout=?, stderr=? WHERE id=? and host=?", tht(id))
|
||||
|
||||
if count == 0 {
|
||||
// 如果是timeout了,后来任务执行完成之后,结果又上来了,stdout和stderr最好还是存库,让用户看到
|
||||
count, err = DB["job"].Table(tht(id)).Where("id=? and host=? and status=?", id, host, "timeout").Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count == 1 {
|
||||
_, err = DB["job"].Exec(sql, status, stdout, stderr, id, host)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec(sql, status, stdout, stderr, id, host); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM task_host_doing WHERE id=? and host=?", id, host); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func WaitingHostList(id int64, limit ...int) ([]TaskHost, error) {
|
||||
var hosts []TaskHost
|
||||
session := DB["job"].Table(tht(id)).Where("id = ? and status = 'waiting'", id).OrderBy("ii")
|
||||
if len(limit) > 0 {
|
||||
session = session.Limit(limit[0])
|
||||
}
|
||||
err := session.Find(&hosts)
|
||||
return hosts, err
|
||||
}
|
||||
|
||||
func WaitingHostCount(id int64) (int64, error) {
|
||||
return DB["job"].Table(tht(id)).Where("id=? and status='waiting'", id).Count()
|
||||
}
|
||||
|
||||
func UnexpectedHostCount(id int64) (int64, error) {
|
||||
return DB["job"].Table(tht(id)).Where("id=? and status in ('failed', 'timeout', 'killfailed')", id).Count()
|
||||
}
|
||||
|
||||
func IngStatusHostCount(id int64) (int64, error) {
|
||||
return DB["job"].Table(tht(id)).Where("id=? and status in ('waiting', 'running', 'killing')", id).Count()
|
||||
}
|
||||
|
||||
func RunWaitingHosts(hosts []TaskHost) error {
|
||||
count := len(hosts)
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
sql := fmt.Sprintf("UPDATE %s SET status=? WHERE id=? and host=?", tht(hosts[i].Id))
|
||||
if _, err := session.Exec(sql, "running", hosts[i].Id, hosts[i].Host); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Insert(&TaskHostDoing{Id: hosts[i].Id, Host: hosts[i].Host, Clock: now, Action: "start"}); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func TaskHostStatus(id int64) ([]TaskHost, error) {
|
||||
var ret []TaskHost
|
||||
err := DB["job"].Table(tht(id)).Cols("id", "host", "status").Where("id=?", id).OrderBy("ii").Find(&ret)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func TaskHostGets(id int64) ([]TaskHost, error) {
|
||||
var ret []TaskHost
|
||||
err := DB["job"].Table(tht(id)).Where("id=?", id).OrderBy("ii").Find(&ret)
|
||||
return ret, err
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package models
|
||||
|
||||
import "sync"
|
||||
|
||||
type TaskHostDoing struct {
|
||||
Id int64
|
||||
Host string
|
||||
Clock int64
|
||||
Action string
|
||||
}
|
||||
|
||||
func DoingHostList(where string, args ...interface{}) ([]TaskHostDoing, error) {
|
||||
var objs []TaskHostDoing
|
||||
err := DB["job"].Where(where, args...).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func DoingHostCount(where string, args ...interface{}) (int64, error) {
|
||||
return DB["job"].Where(where, args...).Count(new(TaskHostDoing))
|
||||
}
|
||||
|
||||
var (
|
||||
doingLock sync.RWMutex
|
||||
doingMaps map[string][]TaskHostDoing
|
||||
)
|
||||
|
||||
func SetDoingCache(v map[string][]TaskHostDoing) {
|
||||
doingLock.Lock()
|
||||
doingMaps = v
|
||||
doingLock.Unlock()
|
||||
}
|
||||
|
||||
func GetDoingCache(k string) []TaskHostDoing {
|
||||
doingLock.RLock()
|
||||
defer doingLock.RUnlock()
|
||||
return doingMaps[k]
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/cache"
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type TaskMeta struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Account string `json:"account"`
|
||||
Batch int `json:"batch"`
|
||||
Tolerance int `json:"tolerance"`
|
||||
Timeout int `json:"timeout"`
|
||||
Pause string `json:"pause"`
|
||||
Script string `json:"script"`
|
||||
Args string `json:"args"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"created" json:"created"`
|
||||
Done bool `xorm:"-" json:"done"`
|
||||
}
|
||||
|
||||
func TaskMetaGet(where string, args ...interface{}) (*TaskMeta, error) {
|
||||
var obj TaskMeta
|
||||
has, err := DB["job"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func taskMetaCacheKey(k string) string {
|
||||
return fmt.Sprintf("/cache/task/meta/%s", k)
|
||||
}
|
||||
|
||||
// TaskMetaGet 根据ID获取任务元信息,会用到内存缓存
|
||||
func TaskMetaGetByID(id interface{}) (*TaskMeta, error) {
|
||||
var obj TaskMeta
|
||||
if err := cache.Get(taskMetaCacheKey(fmt.Sprint(id)), &obj); err == nil {
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
has, err := DB["job"].Where("id=?", id).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cache.Set(taskMetaCacheKey(fmt.Sprint(id)), obj, cache.DEFAULT)
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (m *TaskMeta) CleanFields() error {
|
||||
if m.Batch < 0 {
|
||||
return fmt.Errorf("arg[batch] should be nonnegative")
|
||||
}
|
||||
|
||||
if m.Tolerance < 0 {
|
||||
return fmt.Errorf("arg[tolerance] should be nonnegative")
|
||||
}
|
||||
|
||||
if m.Timeout < 0 {
|
||||
return fmt.Errorf("arg[timeout] should be nonnegative")
|
||||
}
|
||||
|
||||
if m.Timeout > 3600*24 {
|
||||
return fmt.Errorf("arg[timeout] longer than one day")
|
||||
}
|
||||
|
||||
if m.Timeout == 0 {
|
||||
m.Timeout = 30
|
||||
}
|
||||
|
||||
m.Pause = strings.Replace(m.Pause, ",", ",", -1)
|
||||
m.Pause = strings.Replace(m.Pause, " ", "", -1)
|
||||
m.Args = strings.Replace(m.Args, ",", ",", -1)
|
||||
|
||||
if m.Title == "" {
|
||||
return fmt.Errorf("arg[title] is blank")
|
||||
}
|
||||
|
||||
if str.Dangerous(m.Title) {
|
||||
return fmt.Errorf("arg[title] is dangerous")
|
||||
}
|
||||
|
||||
if m.Script == "" {
|
||||
return fmt.Errorf("arg[script] is blank")
|
||||
}
|
||||
|
||||
if str.Dangerous(m.Args) {
|
||||
return fmt.Errorf("arg[args] is dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(m.Pause) {
|
||||
return fmt.Errorf("arg[pause] is dangerous")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TaskMeta) HandleFH(fh string) {
|
||||
i := strings.Index(m.Title, " FH: ")
|
||||
if i > 0 {
|
||||
m.Title = m.Title[:i]
|
||||
}
|
||||
m.Title = m.Title + " FH: " + fh
|
||||
}
|
||||
|
||||
func (m *TaskMeta) Save(hosts []string, action string) error {
|
||||
if err := m.CleanFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.HandleFH(hosts[0])
|
||||
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Insert(m); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
id := m.Id
|
||||
|
||||
if _, err := session.Insert(&TaskScheduler{Id: id}); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Insert(&TaskAction{Id: id, Action: action, Clock: time.Now().Unix()}); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for _, host := range hosts {
|
||||
sql := fmt.Sprintf("INSERT INTO %s(id, host, status) VALUES(%d, '%s', 'waiting')", tht(id), id, host)
|
||||
if _, err := session.Exec(sql); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (m *TaskMeta) Action() (*TaskAction, error) {
|
||||
return TaskActionGet("id=?", m.Id)
|
||||
}
|
||||
|
||||
func (m *TaskMeta) Hosts() ([]TaskHost, error) {
|
||||
var ret []TaskHost
|
||||
err := DB["job"].Table(tht(m.Id)).Where("id=?", m.Id).Cols("id, host, status").OrderBy("ii").Find(&ret)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *TaskMeta) KillHost(host string) error {
|
||||
bean, err := TaskHostGet(m.Id, host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bean == nil {
|
||||
return fmt.Errorf("no such host")
|
||||
}
|
||||
|
||||
if !(bean.Status == "running" || bean.Status == "timeout") {
|
||||
return fmt.Errorf("current status is:%s, cannot kill", bean.Status)
|
||||
}
|
||||
|
||||
if err := redoHost(m.Id, host, "kill"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return statusSet(m.Id, host, "killing")
|
||||
}
|
||||
|
||||
func (m *TaskMeta) IgnoreHost(host string) error {
|
||||
return statusSet(m.Id, host, "ignored")
|
||||
}
|
||||
|
||||
func (m *TaskMeta) RedoHost(host string) error {
|
||||
bean, err := TaskHostGet(m.Id, host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bean == nil {
|
||||
return fmt.Errorf("no such host")
|
||||
}
|
||||
|
||||
if err := redoHost(m.Id, host, "start"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return statusSet(m.Id, host, "running")
|
||||
}
|
||||
|
||||
func statusSet(id int64, host, status string) error {
|
||||
sql := fmt.Sprintf("UPDATE %s SET status=? WHERE id=? and host=?", tht(id))
|
||||
_, err := DB["job"].Exec(sql, status, id, host)
|
||||
return err
|
||||
}
|
||||
|
||||
func redoHost(id int64, host, action string) error {
|
||||
count, err := DB["job"].Where("id=? and host=?", id, host).Count(new(TaskHostDoing))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
if count == 0 {
|
||||
_, err = DB["job"].Exec("INSERT INTO task_host_doing(id,host,clock,action) VALUES(?,?,?,?)", id, host, now, action)
|
||||
} else {
|
||||
_, err = DB["job"].Exec("UPDATE task_host_doing SET clock=?, action=? WHERE id=? and host=? and action <> ?", now, action, id, host, action)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *TaskMeta) HostStrs() ([]string, error) {
|
||||
var ret []string
|
||||
err := DB["job"].Table(tht(m.Id)).Where("id=?", m.Id).Select("host").OrderBy("ii").Find(&ret)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *TaskMeta) Stdouts() ([]TaskHost, error) {
|
||||
var ret []TaskHost
|
||||
err := DB["job"].Table(tht(m.Id)).Where("id=?", m.Id).Cols("id, host, status, stdout").OrderBy("ii").Find(&ret)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *TaskMeta) Stderrs() ([]TaskHost, error) {
|
||||
var ret []TaskHost
|
||||
err := DB["job"].Table(tht(m.Id)).Where("id=?", m.Id).Cols("id, host, status, stderr").OrderBy("ii").Find(&ret)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func TaskMetaTotal(creator, query string, before time.Time) (int64, error) {
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
session = session.Where("created > '" + before.Format("2006-01-02 15:04:05") + "'")
|
||||
|
||||
if creator != "" {
|
||||
session = session.Where("creator=?", creator)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
// q1 q2 -q3
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
if arr[i] == "" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(arr[i], "-") {
|
||||
q := "%" + arr[i][1:] + "%"
|
||||
session = session.Where("title not like ?", q)
|
||||
} else {
|
||||
q := "%" + arr[i] + "%"
|
||||
session = session.Where("title like ?", q)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return session.Count(new(TaskMeta))
|
||||
}
|
||||
|
||||
func TaskMetaGets(creator, query string, before time.Time, limit, offset int) ([]TaskMeta, error) {
|
||||
session := DB["job"].OrderBy("created desc").Limit(limit, offset)
|
||||
|
||||
session = session.Where("created > '" + before.Format("2006-01-02 15:04:05") + "'")
|
||||
|
||||
if creator != "" {
|
||||
session = session.Where("creator=?", creator)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
// q1 q2 -q3
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
if arr[i] == "" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(arr[i], "-") {
|
||||
q := "%" + arr[i][1:] + "%"
|
||||
session = session.Where("title not like ?", q)
|
||||
} else {
|
||||
q := "%" + arr[i] + "%"
|
||||
session = session.Where("title like ?", q)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var objs []TaskMeta
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package models
|
||||
|
||||
type TaskScheduler struct {
|
||||
Id int64
|
||||
Scheduler string
|
||||
}
|
||||
|
||||
func TasksOfScheduler(scheduler string) ([]int64, error) {
|
||||
var ids []int64
|
||||
err := DB["job"].Table("task_scheduler").Where("scheduler=?", scheduler).Select("id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func TakeOverTask(id int64, pre, current string) (bool, error) {
|
||||
ret, err := DB["job"].Exec("UPDATE task_scheduler SET scheduler=? WHERE id = ? and scheduler = ?", current, id, pre)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := ret.RowsAffected()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected > 0, nil
|
||||
}
|
||||
|
||||
func OrphanTaskIds() ([]int64, error) {
|
||||
var ids []int64
|
||||
err := DB["job"].Table("task_scheduler").Where("scheduler = ''").Select("id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func CleanDoneTask(id int64) error {
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM task_scheduler WHERE id = ?", id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM task_action WHERE id = ?", id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type TaskSchedulerHealth struct {
|
||||
Scheduler string
|
||||
Clock time.Time
|
||||
}
|
||||
|
||||
func TaskSchedulerHeartbeat(endpoint string) error {
|
||||
cnt, err := DB["job"].Where("scheduler = ?", endpoint).Count(new(TaskSchedulerHealth))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt == 0 {
|
||||
_, err = DB["job"].Exec("INSERT INTO task_scheduler_health(scheduler, clock) VALUES(?, now())", endpoint)
|
||||
} else {
|
||||
_, err = DB["job"].Exec("UPDATE task_scheduler_health SET clock = now() WHERE scheduler = ?", endpoint)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func DeadTaskSchedulers() ([]string, error) {
|
||||
var arr []string
|
||||
err := DB["job"].Table("task_scheduler_health").Where("clock < DATE_SUB(now(),INTERVAL 10 SECOND)").Select("scheduler").Find(&arr)
|
||||
return arr, err
|
||||
}
|
||||
|
||||
func DelDeadTaskScheduler(scheduler string) error {
|
||||
_, err := DB["job"].Exec("DELETE FROM task_scheduler_health WHERE scheduler = ?", scheduler)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/slice"
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type TaskTpl struct {
|
||||
Id int64 `json:"id"`
|
||||
NodeId int64 `json:"node_id"`
|
||||
Title string `json:"title"`
|
||||
Batch int `json:"batch"`
|
||||
Tolerance int `json:"tolerance"`
|
||||
Timeout int `json:"timeout"`
|
||||
Pause string `json:"pause"`
|
||||
Script string `json:"script"`
|
||||
Args string `json:"args"`
|
||||
Tags string `json:"tags"`
|
||||
Account string `json:"account"`
|
||||
Creator string `json:"creator"`
|
||||
LastUpdated time.Time `xorm:"<-" json:"last_updated"`
|
||||
}
|
||||
|
||||
func TaskTplTotal(nodeId int64, query string) (int64, error) {
|
||||
session := DB["job"].Where("node_id = ?", nodeId)
|
||||
if query == "" {
|
||||
return session.Count(new(TaskTpl))
|
||||
}
|
||||
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
arg := "%" + arr[i] + "%"
|
||||
session = session.And("title like ? or tags like ?", arg, arg)
|
||||
}
|
||||
|
||||
return session.Count(new(TaskTpl))
|
||||
}
|
||||
|
||||
func TaskTplGets(nodeId int64, query string, limit, offset int) ([]TaskTpl, error) {
|
||||
session := DB["job"].Where("node_id = ?", nodeId).OrderBy("title").Limit(limit, offset)
|
||||
|
||||
var tpls []TaskTpl
|
||||
if query == "" {
|
||||
err := session.Find(&tpls)
|
||||
return tpls, err
|
||||
}
|
||||
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
arg := "%" + arr[i] + "%"
|
||||
session = session.And("title like ? or tags like ?", arg, arg)
|
||||
}
|
||||
|
||||
err := session.Find(&tpls)
|
||||
return tpls, err
|
||||
}
|
||||
|
||||
func TaskTplGet(where string, args ...interface{}) (*TaskTpl, error) {
|
||||
var obj TaskTpl
|
||||
has, err := DB["job"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (t *TaskTpl) CleanFields() error {
|
||||
if t.Batch < 0 {
|
||||
return fmt.Errorf("arg[batch] should be nonnegative")
|
||||
}
|
||||
|
||||
if t.Tolerance < 0 {
|
||||
return fmt.Errorf("arg[tolerance] should be nonnegative")
|
||||
}
|
||||
|
||||
if t.Timeout < 0 {
|
||||
return fmt.Errorf("arg[timeout] should be nonnegative")
|
||||
}
|
||||
|
||||
if t.Timeout == 0 {
|
||||
t.Timeout = 30
|
||||
}
|
||||
|
||||
if t.Timeout > 3600*24 {
|
||||
return fmt.Errorf("arg[timeout] longer than one day")
|
||||
}
|
||||
|
||||
t.Pause = strings.Replace(t.Pause, ",", ",", -1)
|
||||
t.Pause = strings.Replace(t.Pause, " ", "", -1)
|
||||
t.Args = strings.Replace(t.Args, ",", ",", -1)
|
||||
t.Tags = strings.Replace(t.Tags, ",", ",", -1)
|
||||
t.Tags = strings.Replace(t.Tags, " ", "", -1)
|
||||
|
||||
if t.Title == "" {
|
||||
return fmt.Errorf("arg[title] is blank")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Title) {
|
||||
return fmt.Errorf("arg[title] is dangerous")
|
||||
}
|
||||
|
||||
if t.Script == "" {
|
||||
return fmt.Errorf("arg[script] is blank")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Args) {
|
||||
return fmt.Errorf("arg[args] is dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Pause) {
|
||||
return fmt.Errorf("arg[pause] is dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Tags) {
|
||||
return fmt.Errorf("arg[tags] is dangerous")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TaskTpl) Save(hosts []string) error {
|
||||
if err := t.CleanFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
cnt, err := session.Where("node_id=? and title=?", t.NodeId, t.Title).Count(new(TaskTpl))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("title[%s] already exists", t.Title)
|
||||
}
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Insert(t); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
host := strings.TrimSpace(hosts[i])
|
||||
if host == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err = session.Exec("INSERT INTO task_tpl_host(id, host) VALUES(?, ?)", t.Id, host); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (t *TaskTpl) Hosts() ([]string, error) {
|
||||
var arr []string
|
||||
err := DB["job"].Table("task_tpl_host").Where("id=?", t.Id).Select("host").OrderBy("ii").Find(&arr)
|
||||
return arr, err
|
||||
}
|
||||
|
||||
func (t *TaskTpl) Update(hosts []string) error {
|
||||
if err := t.CleanFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
cnt, err := session.Where("node_id=? and title=? and id <> ?", t.NodeId, t.Title, t.Id).Count(new(TaskTpl))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("title[%s] already exists", t.Title)
|
||||
}
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Where("id=?", t.Id).Cols("title", "batch", "tolerance", "timeout", "pause", "script", "args", "tags", "account").Update(t); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Exec("DELETE FROM task_tpl_host WHERE id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
host := strings.TrimSpace(hosts[i])
|
||||
if host == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err = session.Exec("INSERT INTO task_tpl_host(id, host) VALUES(?, ?)", t.Id, host); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (t *TaskTpl) Del() error {
|
||||
session := DB["job"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM task_tpl_host WHERE id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM task_tpl WHERE id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (t *TaskTpl) BindTags(tags []string) error {
|
||||
if t.Tags == "" {
|
||||
t.Tags = strings.Join(tags, ",")
|
||||
} else {
|
||||
arr := strings.Split(t.Tags, ",")
|
||||
lst := slice.UniqueString(append(arr, tags...))
|
||||
sort.Strings(lst)
|
||||
t.Tags = strings.Join(lst, ",")
|
||||
}
|
||||
|
||||
_, err := DB["job"].Where("id=?", t.Id).Cols("tags").Update(t)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *TaskTpl) UnbindTags(tags []string) error {
|
||||
if t.Tags == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
arr := strings.Split(t.Tags, ",")
|
||||
lst := slice.SubString(arr, tags)
|
||||
sort.Strings(lst)
|
||||
t.Tags = strings.Join(lst, ",")
|
||||
_, err := DB["job"].Where("id=?", t.Id).Cols("tags").Update(t)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *TaskTpl) UpdateGroup(nodeId int64) error {
|
||||
t.NodeId = nodeId
|
||||
_, err := DB["job"].Where("id=?", t.Id).Cols("node_id").Update(t)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,356 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Team struct {
|
||||
Id int64 `json:"id"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
Note string `json:"note"`
|
||||
Mgmt int `json:"mgmt"`
|
||||
Creator int64 `json:"creator"`
|
||||
LastUpdated time.Time `json:"last_updated" xorm:"<-"`
|
||||
}
|
||||
|
||||
func TeamIdentByIds(ids []int64) ([]string, error) {
|
||||
if len(ids) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var idents []string
|
||||
err := DB["rdb"].Table("team").In("id", ids).Select("ident").Find(&idents)
|
||||
return idents, err
|
||||
}
|
||||
|
||||
func (t *Team) UsersTotal(query string) (int64, error) {
|
||||
session := DB["rdb"].Where("id in (select user_id from team_user where team_id=?)", t.Id)
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("username like ? or dispname like ?", q, q)
|
||||
}
|
||||
|
||||
return session.Count(new(User))
|
||||
}
|
||||
|
||||
type TeamMember struct {
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Dispname string `json:"dispname"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Im string `json:"im"`
|
||||
IsRoot int `json:"is_root"`
|
||||
TeamId int64 `json:"team_id"`
|
||||
IsAdmin int `json:"is_admin"`
|
||||
}
|
||||
|
||||
// UsersGet limit和offset没有用orm来拼接,是因为获取的list会莫名其妙变多
|
||||
func (t *Team) UsersGet(query string, limit, offset int) ([]TeamMember, error) {
|
||||
if query != "" {
|
||||
sql := "select user.id, user.username, user.dispname, user.phone, user.email, user.im, user.is_root, team_user.team_id, team_user.is_admin from user, team_user where user.id=team_user.user_id and team_user.team_id=? and (user.username like ? or user.dispname like ?) order by user.username"
|
||||
q := "%" + query + "%"
|
||||
var objs []TeamMember
|
||||
err := DB["rdb"].SQL(sql, t.Id, q, q).Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
end := offset + limit
|
||||
total := len(objs)
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
return objs[offset:end], nil
|
||||
}
|
||||
|
||||
sql := "select user.id, user.username, user.dispname, user.phone, user.email, user.im, user.is_root, team_user.team_id, team_user.is_admin from user, team_user where user.id=team_user.user_id and team_user.team_id=? order by user.username"
|
||||
var objs []TeamMember
|
||||
err := DB["rdb"].SQL(sql, t.Id).Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
end := offset + limit
|
||||
total := len(objs)
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
return objs[offset:end], nil
|
||||
}
|
||||
|
||||
func (t *Team) Del() error {
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM team_user WHERE team_id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM team WHERE id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (t *Team) CheckFields() error {
|
||||
if len(t.Ident) > 64 {
|
||||
return fmt.Errorf("ident too long")
|
||||
}
|
||||
|
||||
if len(t.Name) > 64 {
|
||||
return fmt.Errorf("name too long")
|
||||
}
|
||||
|
||||
if len(t.Note) > 255 {
|
||||
return fmt.Errorf("note too long")
|
||||
}
|
||||
|
||||
if t.Mgmt != 0 && t.Mgmt != 1 {
|
||||
return fmt.Errorf("mgmt invalid")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Ident) {
|
||||
return fmt.Errorf("ident dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Name) {
|
||||
return fmt.Errorf("name dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Note) {
|
||||
return fmt.Errorf("note dangerous")
|
||||
}
|
||||
|
||||
if strings.ContainsAny(t.Ident, ".%/") {
|
||||
return fmt.Errorf("ident invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Team) Modify(name, note string, mgmt int) error {
|
||||
t.Name = name
|
||||
t.Note = note
|
||||
t.Mgmt = mgmt
|
||||
|
||||
if err := t.CheckFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := t.Update("name", "note", "mgmt")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Team) Update(cols ...string) error {
|
||||
_, err := DB["rdb"].Where("id=?", t.Id).Cols(cols...).Update(t)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Team) BindUser(ids []int64, isadmin int) error {
|
||||
if ids == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cnt := len(ids)
|
||||
if cnt == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if t.Mgmt == 0 && isadmin == 1 {
|
||||
return fmt.Errorf("isadmin invalid cause mgmt=0")
|
||||
}
|
||||
|
||||
ids, err := safeUserIds(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
for i := 0; i < cnt; i++ {
|
||||
if err := teamUserBind(session, t.Id, ids[i], isadmin); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Team) UnbindUser(ids []int64) error {
|
||||
if ids == nil || len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := DB["rdb"].Where("team_id=?", t.Id).In("user_id", ids).Delete(new(TeamUser))
|
||||
return err
|
||||
}
|
||||
|
||||
func TeamAdd(ident, name, note string, mgmt int, creator int64) (int64, error) {
|
||||
t := Team{
|
||||
Ident: ident,
|
||||
Name: name,
|
||||
Note: note,
|
||||
Mgmt: mgmt,
|
||||
Creator: creator,
|
||||
}
|
||||
|
||||
if err := t.CheckFields(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
cnt, err := DB["rdb"].Where("ident=?", ident).Count(new(Team))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return 0, fmt.Errorf("%s already exists", ident)
|
||||
}
|
||||
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, err = session.Insert(&t); err != nil {
|
||||
session.Rollback()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err = teamUserBind(session, t.Id, creator, 1); err != nil {
|
||||
session.Rollback()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return t.Id, session.Commit()
|
||||
}
|
||||
|
||||
func teamUserBind(session *xorm.Session, teamid, userid int64, isadmin int) error {
|
||||
var link TeamUser
|
||||
has, err := session.Where("team_id=? and user_id=?", teamid, userid).Get(&link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if has && isadmin != link.IsAdmin {
|
||||
_, err = session.Exec("UPDATE team_user SET is_admin=? WHERE team_id=? and user_id=?", isadmin, teamid, userid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !has {
|
||||
_, err = session.Insert(&TeamUser{
|
||||
TeamId: teamid,
|
||||
UserId: userid,
|
||||
IsAdmin: isadmin,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TeamGet(where string, args ...interface{}) (*Team, error) {
|
||||
var obj Team
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func TeamTotal(query string) (int64, error) {
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
return DB["rdb"].Where("ident like ? or name like ? or note like ?", q, q, q).Count(new(Team))
|
||||
}
|
||||
|
||||
return DB["rdb"].Count(new(Team))
|
||||
}
|
||||
|
||||
func TeamTotalInIds(ids []int64, query string) (int64, error) {
|
||||
session := DB["rdb"].In("id", ids)
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
return session.Where("ident like ? or name like ? or note like ?", q, q, q).Count(new(Team))
|
||||
}
|
||||
|
||||
return session.Count(new(Team))
|
||||
}
|
||||
|
||||
func TeamGets(query string, limit, offset int) ([]Team, error) {
|
||||
session := DB["rdb"].Limit(limit, offset).OrderBy("ident")
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("ident like ? or name like ? or note like ?", q, q, q)
|
||||
}
|
||||
|
||||
var objs []Team
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func TeamGetsInIds(ids []int64, query string, limit, offset int) ([]Team, error) {
|
||||
session := DB["rdb"].In("id", ids).Limit(limit, offset).OrderBy("ident")
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("ident like ? or name like ? or note like ?", q, q, q)
|
||||
}
|
||||
|
||||
var objs []Team
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func TeamGetByIds(ids []int64) ([]Team, error) {
|
||||
if ids == nil || len(ids) == 0 {
|
||||
return []Team{}, nil
|
||||
}
|
||||
|
||||
var objs []Team
|
||||
err := DB["rdb"].In("id", ids).OrderBy("ident").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func GetTeamsNameByIds(ids string) ([]string, error) {
|
||||
idsStrArr := strings.Split(ids, ",")
|
||||
teamIds := []int64{}
|
||||
for _, tid := range idsStrArr {
|
||||
id, _ := strconv.ParseInt(tid, 10, 64)
|
||||
teamIds = append(teamIds, id)
|
||||
}
|
||||
|
||||
var names []string
|
||||
teams, err := TeamGetByIds(teamIds)
|
||||
if err != nil {
|
||||
return names, err
|
||||
}
|
||||
for _, team := range teams {
|
||||
names = append(names, team.Name)
|
||||
}
|
||||
return names, err
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package models
|
||||
|
||||
type TeamUser struct {
|
||||
TeamId int64 `json:"team_id" xorm:"'team_id'"`
|
||||
UserId int64 `json:"user_id" xorm:"'user_id'"`
|
||||
IsAdmin int `json:"is_admin" xorm:"'is_admin'"`
|
||||
}
|
||||
|
||||
func TeamMembers(tid int64, isAdmin int) ([]User, error) {
|
||||
ids, err := UserIdsByTeamIds([]int64{tid}, isAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ids == nil || len(ids) == 0 {
|
||||
return []User{}, nil
|
||||
}
|
||||
|
||||
return UserGetByIds(ids)
|
||||
}
|
||||
|
||||
func TeamIdsByUserId(uid int64, isAdmin ...int) ([]int64, error) {
|
||||
session := DB["rdb"].Table("team_user").Select("team_id").Where("user_id=?", uid)
|
||||
if len(isAdmin) > 0 {
|
||||
session = session.Where("is_admin=?", isAdmin[0])
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := session.Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func UserIdsByTeamIds(tids []int64, isAdmin ...int) ([]int64, error) {
|
||||
if len(tids) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
session := DB["rdb"].Table("team_user").Select("user_id").In("team_id", tids)
|
||||
if len(isAdmin) > 0 {
|
||||
session = session.Where("is_admin=?", isAdmin[0])
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := session.Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func TeamHasMember(tid, uid int64, isAdmin ...int) (bool, error) {
|
||||
session := DB["rdb"].Where("team_id=? and user_id=?", tid, uid)
|
||||
if len(isAdmin) > 0 {
|
||||
session = session.Where("is_admin=?", isAdmin[0])
|
||||
}
|
||||
|
||||
cnt, err := session.Count(new(TeamUser))
|
||||
return cnt > 0, err
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
// CryptoPass crypto password use salt
|
||||
func CryptoPass(raw string) (string, error) {
|
||||
salt, err := ConfigsGet("salt")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("query salt from mysql fail: %v", err)
|
||||
}
|
||||
|
||||
return str.MD5(salt + "<-*Uk30^96eY*->" + raw), nil
|
||||
}
|
||||
|
||||
func GenUUIDForUser(username string) string {
|
||||
return str.MD5(username + fmt.Sprint(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
// Paths 把长路径切成多个path,比如:
|
||||
// cop.sre.falcon.judge.hna被切成:
|
||||
// cop、cop.sre、cop.sre.falcon、cop.sre.falcon.judge、cop.sre.falcon.judge.hna
|
||||
func Paths(longPath string) []string {
|
||||
names := strings.Split(longPath, ".")
|
||||
count := len(names)
|
||||
paths := make([]string, 0, count)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
paths = append(paths, strings.Join(names[:i], "."))
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
|
@ -0,0 +1,587 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/slice"
|
||||
|
||||
"github.com/toolkits/pkg/cache"
|
||||
"github.com/toolkits/pkg/errors"
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/str"
|
||||
"gopkg.in/ldap.v3"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/rdb/config"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id int64 `json:"id"`
|
||||
UUID string `json:"uuid" xorm:"'uuid'"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"-"`
|
||||
Dispname string `json:"dispname"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Im string `json:"im"`
|
||||
Portrait string `json:"portrait"`
|
||||
Intro string `json:"intro"`
|
||||
IsRoot int `json:"is_root"`
|
||||
LeaderId int64 `json:"leader_id"`
|
||||
LeaderName string `json:"leader_name"`
|
||||
}
|
||||
|
||||
func (u *User) CopyLdapAttr(sr *ldap.SearchResult) {
|
||||
attrs := config.Config.LDAP.Attributes
|
||||
if attrs.Dispname != "" {
|
||||
u.Dispname = sr.Entries[0].GetAttributeValue(attrs.Dispname)
|
||||
}
|
||||
if attrs.Email != "" {
|
||||
u.Email = sr.Entries[0].GetAttributeValue(attrs.Email)
|
||||
}
|
||||
if attrs.Phone != "" {
|
||||
u.Phone = sr.Entries[0].GetAttributeValue(attrs.Phone)
|
||||
}
|
||||
if attrs.Im != "" {
|
||||
u.Im = sr.Entries[0].GetAttributeValue(attrs.Im)
|
||||
}
|
||||
}
|
||||
|
||||
func InitRooter() {
|
||||
var u User
|
||||
has, err := DB["rdb"].Where("username=?", "root").Get(&u)
|
||||
if err != nil {
|
||||
log.Fatalln("cannot query user[root]", err)
|
||||
}
|
||||
|
||||
if has {
|
||||
return
|
||||
}
|
||||
|
||||
pass, err := CryptoPass("root.2020")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
u = User{
|
||||
Username: "root",
|
||||
Password: pass,
|
||||
Dispname: "超管",
|
||||
IsRoot: 1,
|
||||
UUID: GenUUIDForUser("root"),
|
||||
}
|
||||
|
||||
_, err = DB["rdb"].Insert(u)
|
||||
if err != nil {
|
||||
log.Fatalln("cannot insert user[root]")
|
||||
}
|
||||
|
||||
log.Println("user root init done")
|
||||
}
|
||||
|
||||
func LdapLogin(user, pass, clientIP string) error {
|
||||
sr, err := ldapReq(user, pass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go LoginLogNew(user, clientIP, "in")
|
||||
|
||||
var u User
|
||||
has, err := DB["rdb"].Where("username=?", user).Get(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u.CopyLdapAttr(sr)
|
||||
|
||||
if has {
|
||||
if config.Config.LDAP.CoverAttributes {
|
||||
_, err := DB["rdb"].Where("id=?", u.Id).Update(u)
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
u.Username = user
|
||||
u.Password = "******"
|
||||
u.UUID = GenUUIDForUser(user)
|
||||
_, err = DB["rdb"].Insert(u)
|
||||
return err
|
||||
}
|
||||
|
||||
func PassLogin(user, pass, clientIP string) error {
|
||||
var u User
|
||||
has, err := DB["rdb"].Where("username=?", user).Cols("password").Get(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return fmt.Errorf("user[%s] not found", user)
|
||||
}
|
||||
|
||||
loginPass, err := CryptoPass(pass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if loginPass != u.Password {
|
||||
return fmt.Errorf("password error")
|
||||
}
|
||||
|
||||
go LoginLogNew(user, clientIP, "in")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UserGet(where string, args ...interface{}) (*User, error) {
|
||||
var obj User
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (u *User) IsRooter() bool {
|
||||
return u.IsRoot == 1
|
||||
}
|
||||
|
||||
func (u *User) CheckFields() {
|
||||
u.Username = strings.TrimSpace(u.Username)
|
||||
if u.Username == "" {
|
||||
errors.Bomb("username is blank")
|
||||
}
|
||||
|
||||
if str.Dangerous(u.Username) {
|
||||
errors.Bomb("username is dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(u.Dispname) {
|
||||
errors.Bomb("dispname is dangerous")
|
||||
}
|
||||
|
||||
if u.Phone != "" && !str.IsPhone(u.Phone) {
|
||||
errors.Bomb("%s format error", u.Phone)
|
||||
}
|
||||
|
||||
if u.Email != "" && !str.IsMail(u.Email) {
|
||||
errors.Bomb("%s format error", u.Email)
|
||||
}
|
||||
|
||||
if len(u.Username) > 32 {
|
||||
errors.Bomb("username too long")
|
||||
}
|
||||
|
||||
if len(u.Dispname) > 32 {
|
||||
errors.Bomb("dispname too long")
|
||||
}
|
||||
|
||||
if strings.ContainsAny(u.Im, "%'") {
|
||||
errors.Bomb("im invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) Update(cols ...string) error {
|
||||
u.CheckFields()
|
||||
_, err := DB["rdb"].Where("id=?", u.Id).Cols(cols...).Update(u)
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *User) Save() error {
|
||||
u.CheckFields()
|
||||
|
||||
if u.Id > 0 {
|
||||
return fmt.Errorf("user.id[%d] not equal 0", u.Id)
|
||||
}
|
||||
|
||||
cnt, err := DB["rdb"].Where("username=?", u.Username).Count(new(User))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("username already exists")
|
||||
}
|
||||
|
||||
_, err = DB["rdb"].Insert(u)
|
||||
return err
|
||||
}
|
||||
|
||||
func UserTotal(ids []int64, query string) (int64, error) {
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if len(ids) > 0 {
|
||||
session = session.In("id", ids)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
return session.Where("username like ? or dispname like ? or phone like ? or email like ?", q, q, q, q).Count(new(User))
|
||||
}
|
||||
|
||||
return session.Count(new(User))
|
||||
}
|
||||
|
||||
func UserGets(ids []int64, query string, limit, offset int) ([]User, error) {
|
||||
session := DB["rdb"].Limit(limit, offset).OrderBy("username")
|
||||
if len(ids) > 0 {
|
||||
session = session.In("id", ids)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("username like ? or dispname like ? or phone like ? or email like ?", q, q, q, q)
|
||||
}
|
||||
|
||||
var users []User
|
||||
err := session.Find(&users)
|
||||
return users, err
|
||||
}
|
||||
|
||||
func (u *User) Del() error {
|
||||
session := DB["rdb"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM team_user WHERE user_id=?", u.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM role_global_user WHERE user_id=?", u.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM node_admin WHERE user_id=?", u.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM user_token WHERE user_id=?", u.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM user WHERE id=?", u.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (u *User) CanModifyTeam(t *Team) (bool, error) {
|
||||
if u.IsRoot == 1 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if u.Id == t.Creator {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
session := DB["rdb"].Where("team_id=? and user_id=?", t.Id, u.Id)
|
||||
if t.Mgmt == 1 {
|
||||
session = session.Where("is_admin=1")
|
||||
}
|
||||
|
||||
cnt, err := session.Count(new(TeamUser))
|
||||
return cnt > 0, err
|
||||
}
|
||||
|
||||
func (u *User) CheckPermByNode(node *Node, operation string) {
|
||||
if node == nil {
|
||||
errors.Bomb("node is nil")
|
||||
}
|
||||
|
||||
if operation == "" {
|
||||
errors.Bomb("operation is blank")
|
||||
}
|
||||
|
||||
has, err := u.HasPermByNode(node, operation)
|
||||
errors.Dangerous(err)
|
||||
|
||||
if !has {
|
||||
errors.Bomb("no privilege")
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) HasPermByNode(node *Node, operation string) (bool, error) {
|
||||
// 我是超管,自然有权限
|
||||
if u.IsRoot == 1 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 我是path上游的某个admin,自然有权限
|
||||
nodeIds, err := NodeIdsByPaths(Paths(node.Path))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(nodeIds) == 0 {
|
||||
// 这个数据有问题,是个不正常的path
|
||||
return false, nil
|
||||
}
|
||||
|
||||
yes, err := NodesAdminExists(nodeIds, u.Id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if yes {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 都不是,当成普通用户校验
|
||||
// 1. 查看哪些角色包含这个操作(权限点)
|
||||
roleIds, err := RoleIdsHasOp(operation)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(roleIds) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// 2. 用户在上游任一节点绑过任一角色?
|
||||
yes, err = NodeRoleExists(nodeIds, roleIds, u.Username)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return yes, nil
|
||||
}
|
||||
|
||||
func (u *User) CheckPermGlobal(operation string) {
|
||||
has, err := u.HasPermGlobal(operation)
|
||||
errors.Dangerous(err)
|
||||
|
||||
if !has {
|
||||
errors.Bomb("no privilege")
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) HasPermGlobal(operation string) (bool, error) {
|
||||
if u.IsRoot == 1 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
rids, err := RoleIdsHasOp(operation)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("[CheckPermGlobal] RoleIdsHasOp fail: %v, operation: %s", err, operation)
|
||||
}
|
||||
|
||||
if rids == nil || len(rids) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
has, err := UserHasGlobalRole(u.Id, rids)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("[CheckPermGlobal] UserHasGlobalRole fail: %v, username: %s", err, u.Username)
|
||||
}
|
||||
|
||||
return has, nil
|
||||
}
|
||||
|
||||
func UserGetByIds(ids []int64) ([]User, error) {
|
||||
if ids == nil || len(ids) == 0 {
|
||||
return []User{}, nil
|
||||
}
|
||||
|
||||
var objs []User
|
||||
err := DB["rdb"].In("id", ids).OrderBy("username").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func UserGetByNames(names []string) ([]User, error) {
|
||||
if names == nil || len(names) == 0 {
|
||||
return []User{}, nil
|
||||
}
|
||||
|
||||
var objs []User
|
||||
err := DB["rdb"].In("username", names).OrderBy("username").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func UserGetByUUIDs(uuids []string) ([]User, error) {
|
||||
if uuids == nil || len(uuids) == 0 {
|
||||
return []User{}, nil
|
||||
}
|
||||
|
||||
var objs []User
|
||||
err := DB["rdb"].In("uuid", uuids).OrderBy("username").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func UserSearchListInIds(ids []int64, query string, limit, offset int) ([]User, error) {
|
||||
if ids == nil || len(ids) == 0 {
|
||||
return []User{}, nil
|
||||
}
|
||||
|
||||
session := DB["rdb"].In("id", ids)
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("username like ? or dispname like ?", q, q)
|
||||
}
|
||||
|
||||
var objs []User
|
||||
err := session.OrderBy("username").Limit(limit, offset).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func UserSearchTotalInIds(ids []int64, query string) (int64, error) {
|
||||
if ids == nil || len(ids) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
session := DB["rdb"].In("id", ids)
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("username like ? or dispname like ?", q, q)
|
||||
}
|
||||
|
||||
return session.Count(new(User))
|
||||
}
|
||||
|
||||
func safeUserIds(ids []int64) ([]int64, error) {
|
||||
cnt := len(ids)
|
||||
ret := make([]int64, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
user, err := UserGet("id=?", ids[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
ret = append(ret, ids[i])
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func UsernameByUUID(uuid string) string {
|
||||
if uuid == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
var username string
|
||||
if err := cache.Get("user."+uuid, &username); err == nil {
|
||||
return username
|
||||
}
|
||||
|
||||
user, err := UserGet("uuid=?", uuid)
|
||||
if err != nil {
|
||||
logger.Errorf("UserGet(uuid=%s) fail:%v", uuid, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
cache.Set("user."+uuid, user.Username, time.Hour*24)
|
||||
|
||||
return user.Username
|
||||
}
|
||||
|
||||
func UserFillUUIDs() error {
|
||||
var users []User
|
||||
err := DB["rdb"].Find(&users)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := len(users)
|
||||
for i := 0; i < count; i++ {
|
||||
if users[i].UUID == "" {
|
||||
users[i].UUID = GenUUIDForUser(users[i].Username)
|
||||
err = users[i].Update("uuid")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PermResIds 我在某些节点是管理员,或者我在某些节点有此权限点,获取下面的叶子节点挂载的资源列表
|
||||
func (u *User) PermResIds(operation string) ([]int64, error) {
|
||||
nids1, err := NodeIdsIamAdmin(u.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nids2, err := NodeIdsBindingUsernameWithOp(u.Username, operation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nids := append(nids1, nids2...)
|
||||
|
||||
nodes, err := NodeByIds(nids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lids, err := LeafIdsByNodes(nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(lids) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
return ResIdsGetByNodeIds(lids)
|
||||
}
|
||||
|
||||
// NopriResIdents 我没有权限的资源ident列表
|
||||
func (u *User) NopriResIdents(resIds []int64, op string) ([]string, error) {
|
||||
permIds, err := u.PermResIds(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 全量的 - 我有权限的 = 我没有权限的
|
||||
nopris := slice.SubInt64(resIds, permIds)
|
||||
return ResourceIdentsByIds(nopris)
|
||||
}
|
||||
|
||||
func GetUsersNameByIds(ids string) ([]string, error) {
|
||||
var names []string
|
||||
ids = strings.Replace(ids, "[", "", -1)
|
||||
ids = strings.Replace(ids, "]", "", -1)
|
||||
idsStrArr := strings.Split(ids, ",")
|
||||
|
||||
userIds := []int64{}
|
||||
for _, userId := range idsStrArr {
|
||||
id, _ := strconv.ParseInt(userId, 10, 64)
|
||||
userIds = append(userIds, id)
|
||||
}
|
||||
|
||||
users, err := UserGetByIds(userIds)
|
||||
|
||||
if err != nil {
|
||||
return names, err
|
||||
}
|
||||
for _, user := range users {
|
||||
names = append(names, user.Username)
|
||||
}
|
||||
return names, err
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/toolkits/pkg/slice"
|
||||
)
|
||||
|
||||
// TenantsGetByUserId 使用方:工单
|
||||
func TenantsGetByUserId(id int64, withAdmins ...bool) (tenants []Node, err error) {
|
||||
// 校验用户ID是否合法
|
||||
user, err := UserGet("id=?", id)
|
||||
if err != nil {
|
||||
return tenants, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return tenants, fmt.Errorf("no such user, id: %d", id)
|
||||
}
|
||||
|
||||
// 我是管理员的节点ID
|
||||
ids1, err := NodeIdsIamAdmin(user.Id)
|
||||
if err != nil {
|
||||
return tenants, err
|
||||
}
|
||||
|
||||
// 我有授权关系的节点ID
|
||||
ids2, err := NodeIdsBindingUsername(user.Username)
|
||||
if err != nil {
|
||||
return tenants, err
|
||||
}
|
||||
|
||||
// 把节点ID合并之后,对合集求node列表
|
||||
nodes, err := NodeByIds(slice.MergeInt64(ids1, ids2))
|
||||
if err != nil {
|
||||
return tenants, err
|
||||
}
|
||||
|
||||
// 我没有关联任何节点,表示我不属于任何租户
|
||||
count := len(nodes)
|
||||
if count == 0 {
|
||||
return tenants, nil
|
||||
}
|
||||
|
||||
idents := make(map[string]struct{})
|
||||
for i := 0; i < count; i++ {
|
||||
idents[strings.Split(nodes[i].Path, ".")[0]] = struct{}{}
|
||||
}
|
||||
|
||||
for ident := range idents {
|
||||
node, err := NodeGet("path=?", ident)
|
||||
if err != nil {
|
||||
return tenants, err
|
||||
}
|
||||
|
||||
if len(withAdmins) > 0 && withAdmins[0] {
|
||||
err = node.FillAdmins()
|
||||
if err != nil {
|
||||
return tenants, err
|
||||
}
|
||||
}
|
||||
|
||||
tenants = append(tenants, *node)
|
||||
}
|
||||
|
||||
return tenants, nil
|
||||
}
|
||||
|
||||
// UsersGetByGlobalRoleIds 使用方:工单
|
||||
func UsersGetByGlobalRoleIds(ids []int64) (users []User, err error) {
|
||||
if len(ids) == 0 {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
userIds, err := UserIdsGetByRoleIds(ids)
|
||||
if err != nil {
|
||||
return users, err
|
||||
}
|
||||
|
||||
return UserGetByIds(userIds)
|
||||
}
|
||||
|
||||
// GlobalRolesGetByUserId 使用方:工单
|
||||
func GlobalRolesGetByUserId(id int64) (roles []Role, err error) {
|
||||
roleIds, err := RoleIdsGetByUserId(id)
|
||||
if err != nil {
|
||||
return roles, err
|
||||
}
|
||||
|
||||
return RoleGetByIds(roleIds)
|
||||
}
|
||||
|
||||
// GetUsernameByToken 使用方:rbac-proxy
|
||||
func GetUsernameByToken(token string) (string, error) {
|
||||
ut, err := UserTokenGet("token=?", token)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if ut == nil {
|
||||
return "", fmt.Errorf("no such token")
|
||||
}
|
||||
|
||||
return ut.Username, nil
|
||||
}
|
||||
|
||||
// UsernameCandoGlobalOp 使用方:RDB、rbac-proxy
|
||||
func UsernameCandoGlobalOp(username, operation string) (bool, error) {
|
||||
user, err := UserGet("username=?", username)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return false, fmt.Errorf("no such user: %s", username)
|
||||
}
|
||||
|
||||
return user.HasPermGlobal(operation)
|
||||
}
|
||||
|
||||
func UsernameCandoNodeOp(username, operation string, nodeId int64) (bool, error) {
|
||||
user, err := UserGet("username=?", username)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return false, fmt.Errorf("no such user: %s", username)
|
||||
}
|
||||
|
||||
node, err := NodeGet("id=?", nodeId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if node == nil {
|
||||
return false, fmt.Errorf("no such node, id: %d", nodeId)
|
||||
}
|
||||
|
||||
return user.HasPermByNode(node, operation)
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type UserToken struct {
|
||||
UserId int64 `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func UserTokenGet(where string, args ...interface{}) (*UserToken, error) {
|
||||
var obj UserToken
|
||||
has, err := DB["rdb"].Where(where, args...).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func UserTokenGets(where string, args ...interface{}) ([]UserToken, error) {
|
||||
var objs []UserToken
|
||||
err := DB["rdb"].Where(where, args...).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func UserTokenNew(userId int64, username string) (*UserToken, error) {
|
||||
items, err := UserTokenGets("user_id=?", userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(items) >= 2 {
|
||||
return nil, fmt.Errorf("each user has at most two tokens")
|
||||
}
|
||||
|
||||
obj := UserToken{
|
||||
UserId: userId,
|
||||
Username: username,
|
||||
Token: genToken(userId),
|
||||
}
|
||||
|
||||
_, err = DB["rdb"].Insert(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func UserTokenReset(userId int64, token string) (*UserToken, error) {
|
||||
obj, err := UserTokenGet("token=? and user_id=?", token, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj == nil {
|
||||
return nil, fmt.Errorf("no such token")
|
||||
}
|
||||
|
||||
obj.Token = genToken(userId)
|
||||
_, err = DB["rdb"].Where("user_id=? and token=?", userId, token).Cols("token").Update(obj)
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func genToken(userId int64) string {
|
||||
now := time.Now().UnixNano()
|
||||
rls := str.RandLetters(6)
|
||||
return str.MD5(fmt.Sprintf("%d%d%d%s", os.Getpid(), userId, now, rls))
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/didi/nightingale/src/common/loggeri"
|
||||
"github.com/didi/nightingale/src/modules/agent/cache"
|
||||
"github.com/didi/nightingale/src/modules/agent/config"
|
||||
"github.com/didi/nightingale/src/modules/agent/core"
|
||||
"github.com/didi/nightingale/src/modules/agent/http"
|
||||
"github.com/didi/nightingale/src/modules/agent/log/worker"
|
||||
"github.com/didi/nightingale/src/modules/agent/report"
|
||||
"github.com/didi/nightingale/src/modules/agent/stra"
|
||||
"github.com/didi/nightingale/src/modules/agent/sys"
|
||||
"github.com/didi/nightingale/src/modules/agent/sys/funcs"
|
||||
"github.com/didi/nightingale/src/modules/agent/sys/plugins"
|
||||
"github.com/didi/nightingale/src/modules/agent/sys/ports"
|
||||
"github.com/didi/nightingale/src/modules/agent/sys/procs"
|
||||
"github.com/didi/nightingale/src/modules/agent/timer"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/runner"
|
||||
)
|
||||
|
||||
var (
|
||||
vers *bool
|
||||
help *bool
|
||||
conf *string
|
||||
|
||||
version = "No Version Provided"
|
||||
)
|
||||
|
||||
func init() {
|
||||
vers = flag.Bool("v", false, "display the version.")
|
||||
help = flag.Bool("h", false, "print this help.")
|
||||
conf = flag.String("f", "", "specify configuration file.")
|
||||
flag.Parse()
|
||||
|
||||
if *vers {
|
||||
fmt.Println("Version:", version)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if *help {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
runner.Init()
|
||||
fmt.Println("runner.cwd:", runner.Cwd)
|
||||
fmt.Println("runner.hostname:", runner.Hostname)
|
||||
}
|
||||
|
||||
func main() {
|
||||
parseConf()
|
||||
|
||||
loggeri.Init(config.Config.Logger)
|
||||
|
||||
if config.Config.Enable.Mon {
|
||||
monStart()
|
||||
}
|
||||
|
||||
if config.Config.Enable.Job {
|
||||
jobStart()
|
||||
}
|
||||
|
||||
if config.Config.Enable.Report {
|
||||
reportStart()
|
||||
}
|
||||
|
||||
http.Start()
|
||||
|
||||
endingProc()
|
||||
}
|
||||
|
||||
func reportStart() {
|
||||
if err := report.GatherBase(); err != nil {
|
||||
fmt.Println("gatherBase fail: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
go report.LoopReport()
|
||||
}
|
||||
|
||||
func jobStart() {
|
||||
go timer.Heartbeat()
|
||||
}
|
||||
|
||||
func monStart() {
|
||||
sys.Init(config.Config.Sys)
|
||||
stra.Init()
|
||||
|
||||
core.InitRpcClients()
|
||||
funcs.BuildMappers()
|
||||
funcs.Collect()
|
||||
|
||||
//插件采集
|
||||
plugins.Detect()
|
||||
|
||||
//进程采集
|
||||
procs.Detect()
|
||||
|
||||
//端口采集
|
||||
ports.Detect()
|
||||
|
||||
//初始化缓存,用作保存COUNTER类型数据
|
||||
cache.Init()
|
||||
|
||||
//日志采集
|
||||
go worker.UpdateConfigsLoop()
|
||||
go worker.PusherStart()
|
||||
go worker.Zeroize()
|
||||
}
|
||||
|
||||
func parseConf() {
|
||||
if err := config.Parse(); err != nil {
|
||||
fmt.Println("cannot parse configuration file:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func endingProc() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
select {
|
||||
case <-c:
|
||||
fmt.Printf("stop signal caught, stopping... pid=%d\n", os.Getpid())
|
||||
}
|
||||
|
||||
logger.Close()
|
||||
http.Shutdown()
|
||||
fmt.Println("portal stopped successfully")
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/common/dataobj"
|
||||
process "github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
var MetricHistory *History
|
||||
var ProcsCache *ProcessCache
|
||||
|
||||
func Init() {
|
||||
MetricHistory = NewHistory()
|
||||
ProcsCache = NewProcsCache()
|
||||
}
|
||||
|
||||
func NewHistory() *History {
|
||||
h := History{
|
||||
Data: make(map[string]dataobj.MetricValue),
|
||||
}
|
||||
|
||||
go h.Clean()
|
||||
return &h
|
||||
}
|
||||
|
||||
type History struct {
|
||||
sync.RWMutex
|
||||
Data map[string]dataobj.MetricValue
|
||||
}
|
||||
|
||||
func (h *History) Set(key string, item dataobj.MetricValue) {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
h.Data[key] = item
|
||||
}
|
||||
|
||||
func (h *History) Get(key string) (dataobj.MetricValue, bool) {
|
||||
h.RLock()
|
||||
defer h.RUnlock()
|
||||
|
||||
item, exists := h.Data[key]
|
||||
return item, exists
|
||||
}
|
||||
|
||||
func (h *History) Clean() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
h.clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *History) clean() {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
now := time.Now().Unix()
|
||||
for key, item := range h.Data {
|
||||
if now-item.Timestamp > 10*item.Step {
|
||||
delete(h.Data, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ProcessCache struct {
|
||||
sync.RWMutex
|
||||
Data map[int32]*process.Process
|
||||
}
|
||||
|
||||
func NewProcsCache() *ProcessCache {
|
||||
pc := ProcessCache{
|
||||
Data: make(map[int32]*process.Process),
|
||||
}
|
||||
go pc.Clean()
|
||||
return &pc
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) Set(pid int32, p *process.Process) {
|
||||
pc.Lock()
|
||||
defer pc.Unlock()
|
||||
pc.Data[pid] = p
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) Get(pid int32) (*process.Process, bool) {
|
||||
pc.RLock()
|
||||
defer pc.RUnlock()
|
||||
p, exists := pc.Data[pid]
|
||||
return p, exists
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) Clean() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
pc.clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) clean() {
|
||||
pc.Lock()
|
||||
defer pc.Unlock()
|
||||
for pid, procs := range pc.Data {
|
||||
running, _ := procs.IsRunning()
|
||||
if !running {
|
||||
delete(pc.Data, pid)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/rpc"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/net/gobrpc"
|
||||
|
||||
"github.com/didi/nightingale/src/common/address"
|
||||
)
|
||||
|
||||
var cli *gobrpc.RPCClient
|
||||
|
||||
func getCli() *gobrpc.RPCClient {
|
||||
if cli != nil {
|
||||
return cli
|
||||
}
|
||||
|
||||
servers := address.GetRPCAddresses("job")
|
||||
|
||||
// detect the fastest server
|
||||
var (
|
||||
address string
|
||||
client *rpc.Client
|
||||
duration int64 = 999999999999
|
||||
)
|
||||
|
||||
// auto close other slow server
|
||||
acm := make(map[string]*rpc.Client)
|
||||
|
||||
l := len(servers)
|
||||
for i := 0; i < l; i++ {
|
||||
addr := servers[i]
|
||||
begin := time.Now()
|
||||
conn, err := net.DialTimeout("tcp", addr, time.Second*5)
|
||||
if err != nil {
|
||||
logger.Warningf("dial %s fail: %s", addr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
c := rpc.NewClient(conn)
|
||||
acm[addr] = c
|
||||
|
||||
var out string
|
||||
err = c.Call("Scheduler.Ping", "", &out)
|
||||
if err != nil {
|
||||
logger.Warningf("ping %s fail: %s", addr, err)
|
||||
continue
|
||||
}
|
||||
use := time.Since(begin).Nanoseconds()
|
||||
|
||||
if use < duration {
|
||||
address = addr
|
||||
client = c
|
||||
duration = use
|
||||
}
|
||||
}
|
||||
|
||||
if address == "" {
|
||||
logger.Errorf("no job server found")
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Infof("choose server: %s, duration: %dms", address, duration/1000000)
|
||||
|
||||
for addr, c := range acm {
|
||||
if addr == address {
|
||||
continue
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
cli = gobrpc.NewRPCClient(address, client, 5*time.Second)
|
||||
return cli
|
||||
}
|
||||
|
||||
// GetCli 探测所有server端的延迟,自动选择最快的
|
||||
func GetCli() *gobrpc.RPCClient {
|
||||
for {
|
||||
c := getCli()
|
||||
if c != nil {
|
||||
return c
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}
|
||||
|
||||
// CloseCli 关闭客户端连接
|
||||
func CloseCli() {
|
||||
if cli != nil {
|
||||
cli.Close()
|
||||
cli = nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
|
||||
"github.com/didi/nightingale/src/common/dataobj"
|
||||
)
|
||||
|
||||
// Meta 从Server端获取任务元信息
|
||||
func Meta(id int64) (script string, args string, account string, err error) {
|
||||
var resp dataobj.TaskMetaResponse
|
||||
err = GetCli().Call("Scheduler.GetTaskMeta", id, &resp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Message != "" {
|
||||
logger.Error("rpc call Scheduler.GetTaskMeta get error message: ", resp.Message)
|
||||
err = fmt.Errorf(resp.Message)
|
||||
return
|
||||
}
|
||||
|
||||
script = resp.Script
|
||||
args = resp.Args
|
||||
account = resp.Account
|
||||
return
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/toolkits/pkg/file"
|
||||
|
||||
"github.com/didi/nightingale/src/common/identity"
|
||||
"github.com/didi/nightingale/src/common/loggeri"
|
||||
"github.com/didi/nightingale/src/modules/agent/sys"
|
||||
)
|
||||
|
||||
type ConfigT struct {
|
||||
Logger loggeri.Config `yaml:"logger"`
|
||||
Stra straSection `yaml:"stra"`
|
||||
Worker workerSection `yaml:"worker"`
|
||||
Sys sys.SysSection `yaml:"sys"`
|
||||
Enable enableSection `yaml:"enable"`
|
||||
Job jobSection `yaml:"job"`
|
||||
Report reportSection `yaml:"report"`
|
||||
}
|
||||
|
||||
type enableSection struct {
|
||||
Mon bool `yaml:"mon"`
|
||||
Job bool `yaml:"job"`
|
||||
Report bool `yaml:"report"`
|
||||
}
|
||||
|
||||
type reportSection struct {
|
||||
Token string `yaml:"token"`
|
||||
Interval int `yaml:"interval"`
|
||||
Cate string `yaml:"cate"`
|
||||
UniqKey string `yaml:"uniqkey"`
|
||||
SN string `yaml:"sn"`
|
||||
Fields map[string]string `yaml:"fields"`
|
||||
}
|
||||
|
||||
type straSection struct {
|
||||
Enable bool `yaml:"enable"`
|
||||
Interval int `yaml:"interval"`
|
||||
Api string `yaml:"api"`
|
||||
Timeout int `yaml:"timeout"`
|
||||
PortPath string `yaml:"portPath"`
|
||||
ProcPath string `yaml:"procPath"`
|
||||
LogPath string `yaml:"logPath"`
|
||||
}
|
||||
|
||||
type workerSection struct {
|
||||
WorkerNum int `yaml:"workerNum"`
|
||||
QueueSize int `yaml:"queueSize"`
|
||||
PushInterval int `yaml:"pushInterval"`
|
||||
WaitPush int `yaml:"waitPush"`
|
||||
}
|
||||
|
||||
type jobSection struct {
|
||||
MetaDir string `yaml:"metadir"`
|
||||
Interval int `yaml:"interval"`
|
||||
}
|
||||
|
||||
var (
|
||||
Config ConfigT
|
||||
Endpoint string
|
||||
)
|
||||
|
||||
func Parse() error {
|
||||
conf := getYmlFile()
|
||||
|
||||
bs, err := file.ReadBytes(conf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read yml[%s]: %v", conf, err)
|
||||
}
|
||||
|
||||
viper.SetConfigType("yaml")
|
||||
err = viper.ReadConfig(bytes.NewBuffer(bs))
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read yml[%s]: %v", conf, err)
|
||||
}
|
||||
|
||||
viper.SetDefault("worker", map[string]interface{}{
|
||||
"workerNum": 10,
|
||||
"queueSize": 1024000,
|
||||
"pushInterval": 5,
|
||||
"waitPush": 0,
|
||||
})
|
||||
|
||||
viper.SetDefault("stra", map[string]interface{}{
|
||||
"enable": true,
|
||||
"timeout": 1000,
|
||||
"interval": 10, //采集策略更新时间
|
||||
"portPath": "./etc/port",
|
||||
"procPath": "./etc/proc",
|
||||
"logPath": "./etc/log",
|
||||
"api": "/api/mon/collects/",
|
||||
})
|
||||
|
||||
viper.SetDefault("sys", map[string]interface{}{
|
||||
"enable": true,
|
||||
"timeout": 1000, //请求超时时间
|
||||
"interval": 10, //基础指标上报周期
|
||||
"pluginRemote": true, //从monapi获取插件采集配置
|
||||
"plugin": "./plugin",
|
||||
})
|
||||
|
||||
viper.SetDefault("job", map[string]interface{}{
|
||||
"metadir": "./meta",
|
||||
"interval": 2,
|
||||
})
|
||||
|
||||
if err = identity.Parse(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var c ConfigT
|
||||
err = viper.Unmarshal(&c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal config error:%v", err)
|
||||
}
|
||||
|
||||
// 启动的时候就获取一下本机的identity,缓存起来以备后用,优点是性能好,缺点是机器唯一标识发生变化需要重启进程
|
||||
ident, err := identity.GetIdent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("identity:", ident)
|
||||
|
||||
if ident == "" || ident == "127.0.0.1" {
|
||||
return fmt.Errorf("identity[%s] invalid", ident)
|
||||
}
|
||||
|
||||
Endpoint = ident
|
||||
|
||||
c.Job.MetaDir = strings.TrimSpace(c.Job.MetaDir)
|
||||
c.Job.MetaDir, err = file.RealPath(c.Job.MetaDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get absolute filepath of %s fail %v", c.Job.MetaDir, err)
|
||||
}
|
||||
|
||||
if err = file.EnsureDir(c.Job.MetaDir); err != nil {
|
||||
return fmt.Errorf("mkdir -p %s fail: %v", c.Job.MetaDir, err)
|
||||
}
|
||||
|
||||
Config = c
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getYmlFile() string {
|
||||
yml := "etc/agent.local.yml"
|
||||
if file.IsExist(yml) {
|
||||
return yml
|
||||
}
|
||||
|
||||
yml = "etc/agent.yml"
|
||||
if file.IsExist(yml) {
|
||||
return yml
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type RpcClientContainer struct {
|
||||
M map[string]*rpc.Client
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
var rpcClients *RpcClientContainer
|
||||
|
||||
func InitRpcClients() {
|
||||
rpcClients = &RpcClientContainer{
|
||||
M: make(map[string]*rpc.Client),
|
||||
}
|
||||
}
|
||||
|
||||
func (rcc *RpcClientContainer) Get(addr string) *rpc.Client {
|
||||
rcc.RLock()
|
||||
defer rcc.RUnlock()
|
||||
|
||||
client, has := rcc.M[addr]
|
||||
if !has {
|
||||
return nil
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
// Put 返回的bool表示affected,确实把自己塞进去了
|
||||
func (rcc *RpcClientContainer) Put(addr string, client *rpc.Client) bool {
|
||||
rcc.Lock()
|
||||
defer rcc.Unlock()
|
||||
|
||||
oc, has := rcc.M[addr]
|
||||
if has && oc != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
rcc.M[addr] = client
|
||||
return true
|
||||
}
|
||||
|
||||
func (rcc *RpcClientContainer) Del(addr string) {
|
||||
rcc.Lock()
|
||||
defer rcc.Unlock()
|
||||
delete(rcc.M, addr)
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/didi/nightingale/src/common/dataobj"
|
||||
)
|
||||
|
||||
func NewMetricValue(metric string, val interface{}, dataType string, tags ...string) *dataobj.MetricValue {
|
||||
mv := dataobj.MetricValue{
|
||||
Metric: metric,
|
||||
ValueUntyped: val,
|
||||
CounterType: dataType,
|
||||
}
|
||||
|
||||
size := len(tags)
|
||||
|
||||
if size > 0 {
|
||||
mv.Tags = strings.Join(tags, ",")
|
||||
}
|
||||
|
||||
return &mv
|
||||
}
|
||||
|
||||
func GaugeValue(metric string, val interface{}, tags ...string) *dataobj.MetricValue {
|
||||
return NewMetricValue(metric, val, "GAUGE", tags...)
|
||||
}
|
||||
|
||||
func CounterValue(metric string, val interface{}, tags ...string) *dataobj.MetricValue {
|
||||
return NewMetricValue(metric, val, "COUNTER", tags...)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue