2021-06-28 00:42:39 +08:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
2021-07-15 18:46:40 +08:00
|
|
|
"fmt"
|
2021-06-28 00:42:39 +08:00
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
|
|
"github.com/didi/nightingale/v5/models"
|
|
|
|
"github.com/didi/nightingale/v5/pkg/i18n"
|
|
|
|
"github.com/didi/nightingale/v5/pkg/ierr"
|
|
|
|
)
|
|
|
|
|
|
|
|
const defaultLimit = 20
|
|
|
|
|
2021-07-15 18:46:40 +08:00
|
|
|
func _e(format string, a ...interface{}) error {
|
|
|
|
return fmt.Errorf(_s(format, a...))
|
|
|
|
}
|
|
|
|
|
|
|
|
func _s(format string, a ...interface{}) string {
|
|
|
|
return i18n.Sprintf(format, a...)
|
|
|
|
}
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
func dangerous(v interface{}, code ...int) {
|
|
|
|
ierr.Dangerous(v, code...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func bomb(code int, format string, a ...interface{}) {
|
2021-07-15 18:46:40 +08:00
|
|
|
ierr.Bomb(code, _s(format, a...))
|
2021-06-28 00:42:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func bind(c *gin.Context, ptr interface{}) {
|
|
|
|
dangerous(c.ShouldBindJSON(ptr), http.StatusBadRequest)
|
|
|
|
}
|
|
|
|
|
|
|
|
func urlParamStr(c *gin.Context, field string) string {
|
|
|
|
val := c.Param(field)
|
|
|
|
|
|
|
|
if val == "" {
|
|
|
|
bomb(http.StatusBadRequest, "url param[%s] is blank", field)
|
|
|
|
}
|
|
|
|
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
|
|
|
|
func urlParamInt64(c *gin.Context, field string) int64 {
|
|
|
|
strval := urlParamStr(c, field)
|
|
|
|
intval, err := strconv.ParseInt(strval, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
bomb(http.StatusBadRequest, "cannot convert %s to int64", strval)
|
|
|
|
}
|
|
|
|
|
|
|
|
return intval
|
|
|
|
}
|
|
|
|
|
|
|
|
func urlParamInt(c *gin.Context, field string) int {
|
|
|
|
return int(urlParamInt64(c, field))
|
|
|
|
}
|
|
|
|
|
|
|
|
func queryStr(c *gin.Context, key string, defaultVal ...string) string {
|
|
|
|
val := c.Query(key)
|
|
|
|
if val != "" {
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(defaultVal) == 0 {
|
|
|
|
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultVal[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
func queryInt(c *gin.Context, key string, defaultVal ...int) int {
|
|
|
|
strv := c.Query(key)
|
|
|
|
if strv != "" {
|
|
|
|
intv, err := strconv.Atoi(strv)
|
|
|
|
if err != nil {
|
|
|
|
bomb(http.StatusBadRequest, "cannot convert [%s] to int", strv)
|
|
|
|
}
|
|
|
|
return intv
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(defaultVal) == 0 {
|
|
|
|
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultVal[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
func queryInt64(c *gin.Context, key string, defaultVal ...int64) int64 {
|
|
|
|
strv := c.Query(key)
|
|
|
|
if strv != "" {
|
|
|
|
intv, err := strconv.ParseInt(strv, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
bomb(http.StatusBadRequest, "cannot convert [%s] to int64", strv)
|
|
|
|
}
|
|
|
|
return intv
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(defaultVal) == 0 {
|
|
|
|
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultVal[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
func queryBool(c *gin.Context, key string, defaultVal ...bool) bool {
|
|
|
|
strv := c.Query(key)
|
|
|
|
if strv != "" {
|
|
|
|
if strv == "true" || strv == "1" || strv == "on" || strv == "checked" || strv == "yes" || strv == "Y" {
|
|
|
|
return true
|
|
|
|
} else if strv == "false" || strv == "0" || strv == "off" || strv == "no" || strv == "N" {
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
bomb(http.StatusBadRequest, "unknown arg[%s] value: %s", key, strv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(defaultVal) == 0 {
|
|
|
|
bomb(http.StatusBadRequest, "arg[%s] is necessary", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultVal[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
func offset(c *gin.Context, limit int) int {
|
|
|
|
if limit <= 0 {
|
|
|
|
limit = 10
|
|
|
|
}
|
|
|
|
|
|
|
|
page := queryInt(c, "p", 1)
|
|
|
|
return (page - 1) * limit
|
|
|
|
}
|
|
|
|
|
|
|
|
func renderMessage(c *gin.Context, v interface{}, statusCode ...int) {
|
|
|
|
code := 200
|
|
|
|
if len(statusCode) > 0 {
|
|
|
|
code = statusCode[0]
|
|
|
|
}
|
|
|
|
if v == nil {
|
|
|
|
c.JSON(code, gin.H{"err": ""})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch t := v.(type) {
|
|
|
|
case string:
|
2021-07-15 18:46:40 +08:00
|
|
|
c.JSON(code, gin.H{"err": _s(t)})
|
2021-06-28 00:42:39 +08:00
|
|
|
case error:
|
|
|
|
c.JSON(code, gin.H{"err": t.Error()})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func renderData(c *gin.Context, data interface{}, err error, statusCode ...int) {
|
|
|
|
code := 200
|
|
|
|
if len(statusCode) > 0 {
|
|
|
|
code = statusCode[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
c.JSON(code, gin.H{"dat": data, "err": ""})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
renderMessage(c, err.Error(), code)
|
|
|
|
}
|
|
|
|
|
|
|
|
func renderZeroPage(c *gin.Context) {
|
|
|
|
renderData(c, gin.H{
|
|
|
|
"list": []int{},
|
|
|
|
"total": 0,
|
|
|
|
}, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
type idsForm struct {
|
|
|
|
Ids []int64 `json:"ids"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f idsForm) Validate() {
|
|
|
|
if len(f.Ids) == 0 {
|
|
|
|
bomb(http.StatusBadRequest, "ids empty")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func cookieUsername(c *gin.Context) string {
|
|
|
|
session := sessions.Default(c)
|
|
|
|
|
|
|
|
value := session.Get("username")
|
|
|
|
if value == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
return value.(string)
|
|
|
|
}
|
|
|
|
|
|
|
|
func headerUsername(c *gin.Context) string {
|
|
|
|
token := c.GetHeader("Authorization")
|
|
|
|
if token == "" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
ut, err := models.UserTokenGet("token=?", strings.TrimPrefix(token, "Bearer "))
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
if ut == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
return ut.Username
|
|
|
|
}
|
|
|
|
|
|
|
|
// must get username
|
|
|
|
func loginUsername(c *gin.Context) string {
|
|
|
|
usernameInterface, has := c.Get("username")
|
|
|
|
if has {
|
|
|
|
return usernameInterface.(string)
|
|
|
|
}
|
|
|
|
|
|
|
|
username := cookieUsername(c)
|
|
|
|
if username == "" {
|
|
|
|
username = headerUsername(c)
|
|
|
|
}
|
|
|
|
|
2021-08-04 11:05:54 +08:00
|
|
|
if username == "" {
|
|
|
|
remoteAddr := c.Request.RemoteAddr
|
|
|
|
idx := strings.LastIndex(remoteAddr, ":")
|
|
|
|
ip := ""
|
|
|
|
if idx > 0 {
|
|
|
|
ip = remoteAddr[0:idx]
|
|
|
|
}
|
|
|
|
|
|
|
|
if ip == "127.0.0.1" {
|
|
|
|
//本地调用都当成是root用户在调用
|
|
|
|
username = "root"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
if username == "" {
|
|
|
|
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Set("username", username)
|
|
|
|
return username
|
|
|
|
}
|
|
|
|
|
|
|
|
func loginUser(c *gin.Context) *models.User {
|
|
|
|
username := loginUsername(c)
|
|
|
|
|
|
|
|
user, err := models.UserGetByUsername(username)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if user == nil {
|
|
|
|
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
|
|
|
|
}
|
|
|
|
|
|
|
|
if user.Status == 1 {
|
|
|
|
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
|
|
|
|
}
|
|
|
|
|
|
|
|
return user
|
|
|
|
}
|
|
|
|
|
|
|
|
func User(id int64) *models.User {
|
|
|
|
obj, err := models.UserGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such user")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func UserGroup(id int64) *models.UserGroup {
|
|
|
|
obj, err := models.UserGroupGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such user group")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func Classpath(id int64) *models.Classpath {
|
|
|
|
obj, err := models.ClasspathGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such classpath")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func Mute(id int64) *models.Mute {
|
|
|
|
obj, err := models.MuteGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such mute config")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func Dashboard(id int64) *models.Dashboard {
|
|
|
|
obj, err := models.DashboardGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such dashboard")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func ChartGroup(id int64) *models.ChartGroup {
|
|
|
|
obj, err := models.ChartGroupGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such chart group")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func Chart(id int64) *models.Chart {
|
|
|
|
obj, err := models.ChartGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such chart")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func AlertRule(id int64) *models.AlertRule {
|
|
|
|
obj, err := models.AlertRuleGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such alert rule")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func AlertRuleGroup(id int64) *models.AlertRuleGroup {
|
|
|
|
obj, err := models.AlertRuleGroupGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such alert rule group")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func AlertEvent(id int64) *models.AlertEvent {
|
|
|
|
obj, err := models.AlertEventGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such alert event")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
2021-08-06 12:16:32 +08:00
|
|
|
func HistoryAlertEvent(id int64) *models.HistoryAlertEvent {
|
|
|
|
obj, err := models.HistoryAlertEventGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such alert all event")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
func CollectRule(id int64) *models.CollectRule {
|
|
|
|
obj, err := models.CollectRuleGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such collect rule")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func MetricDescription(id int64) *models.MetricDescription {
|
|
|
|
obj, err := models.MetricDescriptionGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such metric description")
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func Resource(id int64) *models.Resource {
|
|
|
|
obj, err := models.ResourceGet("id=?", id)
|
|
|
|
dangerous(err)
|
|
|
|
|
|
|
|
if obj == nil {
|
|
|
|
bomb(http.StatusNotFound, "No such resource")
|
|
|
|
}
|
|
|
|
|
|
|
|
classpathResources, err := models.ClasspathResourceGets("res_ident=?", obj.Ident)
|
|
|
|
dangerous(err)
|
|
|
|
for _, cr := range classpathResources {
|
|
|
|
obj.ClasspathIds = append(obj.ClasspathIds, cr.ClasspathId)
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}
|