Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75662586fa | ||
|
|
c024331fa0 | ||
|
|
b01ea79c5c | ||
|
|
d59f80b3ec | ||
|
|
b87e48c1f9 | ||
|
|
0e7a7f168f | ||
|
|
2bbc09d3af | ||
|
|
97b50fab28 | ||
|
|
83c867cb65 | ||
|
|
3c4b7ca57b | ||
|
|
a2f98d2f25 | ||
|
|
71677a8638 | ||
|
|
95a2187f95 | ||
|
|
86bec813bf | ||
|
|
0d7bd6f04e | ||
|
|
d7117209b2 | ||
|
|
7a340ac68b | ||
|
|
353b1b4ad1 | ||
|
|
fdac8beb40 | ||
|
|
f098723a41 | ||
|
|
6ded627903 | ||
|
|
ed2d5ee5cc | ||
|
|
c677368482 | ||
|
|
51ccd614a7 | ||
|
|
9be7f61b8c | ||
|
|
14ad97c937 | ||
|
|
94609d8ef4 | ||
|
|
e34e38bcb2 | ||
|
|
b10d9fe842 | ||
|
|
992e725378 | ||
|
|
346de7ca7a |
29
LICENSE
Normal file
29
LICENSE
Normal file
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020, LiuXiangChao
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/apps"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
@@ -21,12 +23,12 @@ func main() {
|
||||
if !Tea.IsTesting() {
|
||||
Tea.Env = "prod"
|
||||
}
|
||||
app := apps.NewAppCmd()
|
||||
var app = apps.NewAppCmd()
|
||||
app.Version(teaconst.Version)
|
||||
app.Product(teaconst.ProductName)
|
||||
app.Usage(teaconst.ProcessName + " [start|stop|restart|setup|upgrade|service|daemon]")
|
||||
app.Usage(teaconst.ProcessName + " [start|stop|restart|setup|upgrade|service|daemon|issues]")
|
||||
app.On("setup", func() {
|
||||
setupCmd := setup.NewSetupFromCmd()
|
||||
var setupCmd = setup.NewSetupFromCmd()
|
||||
err := setupCmd.Run()
|
||||
result := maps.Map{}
|
||||
if err != nil {
|
||||
@@ -122,6 +124,43 @@ func main() {
|
||||
fmt.Println("prepared statements count: " + types.String(count))
|
||||
}
|
||||
})
|
||||
app.On("issues", func() {
|
||||
var flagSet = flag.NewFlagSet("issues", flag.ExitOnError)
|
||||
var formatJSON = false
|
||||
flagSet.BoolVar(&formatJSON, "json", false, "")
|
||||
_ = flagSet.Parse(os.Args[2:])
|
||||
|
||||
data, err := ioutil.ReadFile(Tea.LogFile("issues.log"))
|
||||
if err != nil {
|
||||
if formatJSON {
|
||||
fmt.Print("[]")
|
||||
} else {
|
||||
fmt.Println("no issues yet")
|
||||
}
|
||||
} else {
|
||||
var issueMaps = []maps.Map{}
|
||||
err = json.Unmarshal(data, &issueMaps)
|
||||
if err != nil {
|
||||
if formatJSON {
|
||||
fmt.Print("[]")
|
||||
} else {
|
||||
fmt.Println("no issues yet")
|
||||
}
|
||||
} else {
|
||||
if formatJSON {
|
||||
fmt.Print(string(data))
|
||||
} else {
|
||||
if len(issueMaps) == 0 {
|
||||
fmt.Println("no issues yet")
|
||||
} else {
|
||||
for i, issue := range issueMaps {
|
||||
fmt.Println("issue " + types.String(i+1) + ": " + issue.GetString("message"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.Run(func() {
|
||||
nodes.NewAPINode().Start()
|
||||
|
||||
2
go.mod
2
go.mod
@@ -12,7 +12,7 @@ require (
|
||||
github.com/go-acme/lego/v4 v4.5.2
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/iwind/TeaGo v0.0.0-20220408064305-92be81dc2f7c
|
||||
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mozillazg/go-pinyin v0.18.0
|
||||
|
||||
2
go.sum
2
go.sum
@@ -242,6 +242,8 @@ github.com/iwind/TeaGo v0.0.0-20220322141208-22f88d04004d h1:e8fkTKras/RXQWECApM
|
||||
github.com/iwind/TeaGo v0.0.0-20220322141208-22f88d04004d/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||
github.com/iwind/TeaGo v0.0.0-20220408064305-92be81dc2f7c h1:ugjYZ74FJGWlfDKKraNgMyDTeS4vbXHe89JGUVQIJMo=
|
||||
github.com/iwind/TeaGo v0.0.0-20220408064305-92be81dc2f7c/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570 h1:zqz2FiMMkSHXWO1EsTRJDPTwX9xQ4uuyD5GAE4JGlhM=
|
||||
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||
github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
|
||||
@@ -44,7 +44,7 @@ func (this *BaseStorage) Marshal(accessLog *pb.HTTPAccessLog) ([]byte, error) {
|
||||
|
||||
// FormatVariables 格式化字符串中的变量
|
||||
func (this *BaseStorage) FormatVariables(s string) string {
|
||||
now := time.Now()
|
||||
var now = time.Now()
|
||||
return configutils.ParseVariables(s, func(varName string) (value string) {
|
||||
switch varName {
|
||||
case "year":
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
@@ -95,7 +97,10 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
|
||||
args = append(args, "-S", "10240")
|
||||
|
||||
cmd := exec.Command(this.exe, args...)
|
||||
var cmd = exec.Command(this.exe, args...)
|
||||
var stderrBuffer = &bytes.Buffer{}
|
||||
cmd.Stderr = stderrBuffer
|
||||
|
||||
w, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -111,7 +116,7 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
}
|
||||
data, err := this.Marshal(accessLog)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "marshal accesslog failed: "+err.Error())
|
||||
continue
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
@@ -121,14 +126,15 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
|
||||
_, err = w.Write([]byte("\n"))
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "write accesslog failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
_ = w.Close()
|
||||
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.New("send syslog failed: " + err.Error() + ", stderr: " + stderrBuffer.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.4.7"
|
||||
Version = "0.4.8"
|
||||
|
||||
ProductName = "Edge API"
|
||||
ProcessName = "edge-api"
|
||||
@@ -18,13 +18,13 @@ const (
|
||||
|
||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||
|
||||
NodeVersion = "0.4.7"
|
||||
UserNodeVersion = "0.3.3"
|
||||
NodeVersion = "0.4.8.1"
|
||||
UserNodeVersion = "0.3.4"
|
||||
AuthorityNodeVersion = "0.0.2"
|
||||
MonitorNodeVersion = "0.0.3"
|
||||
DNSNodeVersion = "0.2.2"
|
||||
ReportNodeVersion = "0.1.0"
|
||||
MonitorNodeVersion = "0.0.4"
|
||||
DNSNodeVersion = "0.2.3"
|
||||
ReportNodeVersion = "0.1.1"
|
||||
|
||||
// SQLVersion SQL版本号
|
||||
SQLVersion = "8"
|
||||
SQLVersion = "11"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package authority
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
@@ -188,13 +189,19 @@ func (this *AuthorityNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
|
||||
}
|
||||
|
||||
// UpdateNodeStatus 更改节点状态
|
||||
func (this *AuthorityNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
|
||||
if statusJSON == nil {
|
||||
func (this *AuthorityNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
|
||||
if nodeStatus == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := this.Query(tx).
|
||||
|
||||
nodeStatusJSON, err := json.Marshal(nodeStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("status", string(statusJSON)).
|
||||
Set("status", nodeStatusJSON).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func (this *DNSProviderDAO) UpdateDNSProvider(tx *dbs.Tx, dnsProviderId int64, n
|
||||
}
|
||||
|
||||
// CountAllEnabledDNSProviders 计算服务商数量
|
||||
func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, domain string) (int64, error) {
|
||||
func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, domain string, providerType string) (int64, error) {
|
||||
var query = dbutils.NewQuery(tx, this, adminId, userId)
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword)").
|
||||
@@ -119,12 +119,16 @@ func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int6
|
||||
query.Param("domain", domain)
|
||||
}
|
||||
|
||||
if len(providerType) > 0 {
|
||||
query.Attr("type", providerType)
|
||||
}
|
||||
|
||||
return query.State(DNSProviderStateEnabled).
|
||||
Count()
|
||||
}
|
||||
|
||||
// ListEnabledDNSProviders 列出单页服务商
|
||||
func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, domain string, offset int64, size int64) (result []*DNSProvider, err error) {
|
||||
func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, domain string, providerType string, offset int64, size int64) (result []*DNSProvider, err error) {
|
||||
var query = dbutils.NewQuery(tx, this, adminId, userId)
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword)").
|
||||
@@ -134,6 +138,9 @@ func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, u
|
||||
query.Where("id IN (SELECT providerId FROM " + SharedDNSDomainDAO.Table + " WHERE state=1 AND name=:domain)")
|
||||
query.Param("domain", domain)
|
||||
}
|
||||
if len(providerType) > 0 {
|
||||
query.Attr("type", providerType)
|
||||
}
|
||||
_, err = query.
|
||||
State(DNSProviderStateEnabled).
|
||||
Offset(offset).
|
||||
|
||||
@@ -395,9 +395,14 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
|
||||
|
||||
var locker = sync.Mutex{}
|
||||
|
||||
// 这里正则表达式中的括号不能轻易变更,因为后面有引用
|
||||
// TODO 支持多个查询条件的组合,比如 status:200 proto:HTTP/1.1
|
||||
var statusPrefixReg = regexp.MustCompile(`status:\s*(\d{3})\b`)
|
||||
var statusRangeReg = regexp.MustCompile(`status:\s*(\d{3})-(\d{3})\b`)
|
||||
var urlReg = regexp.MustCompile(`^(http|https)://`)
|
||||
var requestPathReg = regexp.MustCompile(`requestPath:(\S+)`)
|
||||
var protoReg = regexp.MustCompile(`proto:(\S+)`)
|
||||
var schemeReg = regexp.MustCompile(`scheme:(\S+)`)
|
||||
|
||||
var count = len(tableQueries)
|
||||
var wg = &sync.WaitGroup{}
|
||||
@@ -509,13 +514,25 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
|
||||
isSpecialKeyword = true
|
||||
var matches = statusRangeReg.FindStringSubmatch(keyword)
|
||||
query.Between("status", types.Int(matches[1]), types.Int(matches[2]))
|
||||
|
||||
// TODO 处理剩余的关键词
|
||||
} else if statusPrefixReg.MatchString(keyword) { // status:200
|
||||
isSpecialKeyword = true
|
||||
var matches = statusPrefixReg.FindStringSubmatch(keyword)
|
||||
query.Attr("status", matches[1])
|
||||
// TODO 处理剩余的关键词
|
||||
} else if requestPathReg.MatchString(keyword) {
|
||||
isSpecialKeyword = true
|
||||
var matches = requestPathReg.FindStringSubmatch(keyword)
|
||||
query.Where("JSON_EXTRACT(content, '$.requestPath')=:keyword").
|
||||
Param("keyword", matches[1])
|
||||
} else if protoReg.MatchString(keyword) {
|
||||
isSpecialKeyword = true
|
||||
var matches = protoReg.FindStringSubmatch(keyword)
|
||||
query.Where("JSON_EXTRACT(content, '$.proto')=:keyword").
|
||||
Param("keyword", strings.ToUpper(matches[1]))
|
||||
} else if schemeReg.MatchString(keyword) {
|
||||
isSpecialKeyword = true
|
||||
var matches = schemeReg.FindStringSubmatch(keyword)
|
||||
query.Where("JSON_EXTRACT(content, '$.scheme')=:keyword").
|
||||
Param("keyword", strings.ToLower(matches[1]))
|
||||
} else if urlReg.MatchString(keyword) { // https://xxx/yyy
|
||||
u, err := url.Parse(keyword)
|
||||
if err == nil {
|
||||
|
||||
254
internal/db/models/http_cache_task_dao.go
Normal file
254
internal/db/models/http_cache_task_dao.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
HTTPCacheTaskStateEnabled = 1 // 已启用
|
||||
HTTPCacheTaskStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type HTTPCacheTaskType = string
|
||||
|
||||
const (
|
||||
HTTPCacheTaskTypePurge HTTPCacheTaskType = "purge"
|
||||
HTTPCacheTaskTypeFetch HTTPCacheTaskType = "fetch"
|
||||
)
|
||||
|
||||
type HTTPCacheTaskDAO dbs.DAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReadyDone(func() {
|
||||
// 清理数据任务
|
||||
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||
goman.New(func() {
|
||||
for range ticker.C {
|
||||
err := SharedHTTPCacheTaskDAO.Clean(nil, 30) // 只保留N天
|
||||
if err != nil {
|
||||
remotelogs.Error("HTTPCacheTaskDAO", "clean expired data failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func NewHTTPCacheTaskDAO() *HTTPCacheTaskDAO {
|
||||
return dbs.NewDAO(&HTTPCacheTaskDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeHTTPCacheTasks",
|
||||
Model: new(HTTPCacheTask),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*HTTPCacheTaskDAO)
|
||||
}
|
||||
|
||||
var SharedHTTPCacheTaskDAO *HTTPCacheTaskDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedHTTPCacheTaskDAO = NewHTTPCacheTaskDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// EnableHTTPCacheTask 启用条目
|
||||
func (this *HTTPCacheTaskDAO) EnableHTTPCacheTask(tx *dbs.Tx, taskId int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(taskId).
|
||||
Set("state", HTTPCacheTaskStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableHTTPCacheTask 禁用条目
|
||||
func (this *HTTPCacheTaskDAO) DisableHTTPCacheTask(tx *dbs.Tx, taskId int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(taskId).
|
||||
Set("state", HTTPCacheTaskStateDisabled).
|
||||
Update()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return this.NotifyChange(tx, taskId)
|
||||
}
|
||||
|
||||
// FindEnabledHTTPCacheTask 查找启用中的条目
|
||||
func (this *HTTPCacheTaskDAO) FindEnabledHTTPCacheTask(tx *dbs.Tx, taskId int64) (*HTTPCacheTask, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(taskId).
|
||||
Attr("state", HTTPCacheTaskStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*HTTPCacheTask), err
|
||||
}
|
||||
|
||||
// CreateTask 创建任务
|
||||
func (this *HTTPCacheTaskDAO) CreateTask(tx *dbs.Tx, userId int64, taskType HTTPCacheTaskType, keyType string, description string) (int64, error) {
|
||||
var op = NewHTTPCacheTaskOperator()
|
||||
op.UserId = userId
|
||||
op.Type = taskType
|
||||
op.KeyType = keyType
|
||||
op.IsOk = false
|
||||
op.IsDone = false
|
||||
op.IsReady = false
|
||||
op.Description = description
|
||||
op.Day = timeutil.Format("Ymd")
|
||||
op.State = HTTPCacheTaskStateEnabled
|
||||
taskId, err := this.SaveInt64(tx, op)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = this.NotifyChange(tx, taskId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return taskId, nil
|
||||
}
|
||||
|
||||
// ResetTask 重置服务状态
|
||||
func (this *HTTPCacheTaskDAO) ResetTask(tx *dbs.Tx, taskId int64) error {
|
||||
if taskId <= 0 {
|
||||
return errors.New("invalid 'taskId'")
|
||||
}
|
||||
|
||||
var op = NewHTTPCacheTaskOperator()
|
||||
op.Id = taskId
|
||||
op.IsOk = false
|
||||
op.IsDone = false
|
||||
op.DoneAt = 0
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
// UpdateTaskReady 设置任务为已准备
|
||||
func (this *HTTPCacheTaskDAO) UpdateTaskReady(tx *dbs.Tx, taskId int64) error {
|
||||
return this.Query(tx).
|
||||
Pk(taskId).
|
||||
Set("isReady", true).
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// CountTasks 查询所有任务数量
|
||||
func (this *HTTPCacheTaskDAO) CountTasks(tx *dbs.Tx, userId int64) (int64, error) {
|
||||
var query = this.Query(tx).
|
||||
State(HTTPCacheTaskStateEnabled).
|
||||
Attr("isReady", true)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// CountDoingTasks 查询正在执行的任务数量
|
||||
func (this *HTTPCacheTaskDAO) CountDoingTasks(tx *dbs.Tx, userId int64) (int64, error) {
|
||||
var query = this.Query(tx).
|
||||
State(HTTPCacheTaskStateEnabled).
|
||||
Attr("isReady", true).
|
||||
Attr("isDone", false)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListTasks 列出单页任务
|
||||
func (this *HTTPCacheTaskDAO) ListTasks(tx *dbs.Tx, userId int64, offset int64, size int64) (result []*HTTPCacheTask, err error) {
|
||||
var query = this.Query(tx).
|
||||
State(HTTPCacheTaskStateEnabled).
|
||||
Attr("isReady", true)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
_, err = query.
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
DescPk().
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// ListDoingTasks 列出需要执行的任务
|
||||
func (this *HTTPCacheTaskDAO) ListDoingTasks(tx *dbs.Tx, size int64) (result []*HTTPCacheTask, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(HTTPCacheTaskStateEnabled).
|
||||
Attr("isDone", false).
|
||||
Attr("isReady", true).
|
||||
Limit(size).
|
||||
AscPk(). // 按照先创建先执行的原则
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateTaskStatus 标记任务已完成
|
||||
func (this *HTTPCacheTaskDAO) UpdateTaskStatus(tx *dbs.Tx, taskId int64, isDone bool, isOk bool) error {
|
||||
if taskId <= 0 {
|
||||
return errors.New("invalid taskId '" + types.String(taskId) + "'")
|
||||
}
|
||||
var op = NewHTTPCacheTaskOperator()
|
||||
op.Id = taskId
|
||||
op.IsDone = isDone
|
||||
op.IsOk = isOk
|
||||
|
||||
if isDone {
|
||||
op.DoneAt = time.Now().Unix()
|
||||
}
|
||||
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
// CheckUserTask 检查用户任务
|
||||
func (this *HTTPCacheTaskDAO) CheckUserTask(tx *dbs.Tx, userId int64, taskId int64) error {
|
||||
b, err := this.Query(tx).
|
||||
Pk(taskId).
|
||||
Attr("userId", userId).
|
||||
State(HTTPCacheTaskStateEnabled).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !b {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clean 清理以往的任务
|
||||
func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error {
|
||||
if days <= 0 {
|
||||
days = 30
|
||||
}
|
||||
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
|
||||
|
||||
// 删除Key
|
||||
err := SharedHTTPCacheTaskKeyDAO.Clean(tx, days)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除任务
|
||||
_, err = this.Query(tx).
|
||||
Lte("day", day).
|
||||
Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
// NotifyChange 发送通知
|
||||
func (this *HTTPCacheTaskDAO) NotifyChange(tx *dbs.Tx, taskId int64) error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
19
internal/db/models/http_cache_task_dao_test.go
Normal file
19
internal/db/models/http_cache_task_dao_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHTTPCacheTaskDAO_Clean(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
err := models.SharedHTTPCacheTaskDAO.Clean(nil, 30)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
218
internal/db/models/http_cache_task_key_dao.go
Normal file
218
internal/db/models/http_cache_task_key_dao.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type HTTPCacheTaskKeyDAO dbs.DAO
|
||||
|
||||
func NewHTTPCacheTaskKeyDAO() *HTTPCacheTaskKeyDAO {
|
||||
return dbs.NewDAO(&HTTPCacheTaskKeyDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeHTTPCacheTaskKeys",
|
||||
Model: new(HTTPCacheTaskKey),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*HTTPCacheTaskKeyDAO)
|
||||
}
|
||||
|
||||
var SharedHTTPCacheTaskKeyDAO *HTTPCacheTaskKeyDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedHTTPCacheTaskKeyDAO = NewHTTPCacheTaskKeyDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// CreateKey 创建Key
|
||||
// 参数:
|
||||
// - clusterId 集群ID
|
||||
// - nodeMapJSON 集群下节点映射,格式类似于 `{ "节点1":true, ... }`
|
||||
func (this *HTTPCacheTaskKeyDAO) CreateKey(tx *dbs.Tx, taskId int64, key string, taskType HTTPCacheTaskType, keyType string, clusterId int64) (int64, error) {
|
||||
var op = NewHTTPCacheTaskKeyOperator()
|
||||
op.TaskId = taskId
|
||||
op.Key = key
|
||||
op.Type = taskType
|
||||
op.KeyType = keyType
|
||||
op.ClusterId = clusterId
|
||||
|
||||
op.Nodes = "{}"
|
||||
op.Errors = "{}"
|
||||
|
||||
return this.SaveInt64(tx, op)
|
||||
}
|
||||
|
||||
// UpdateKeyStatus 修改Key状态
|
||||
func (this *HTTPCacheTaskKeyDAO) UpdateKeyStatus(tx *dbs.Tx, keyId int64, nodeId int64, errString string, nodesJSON []byte) error {
|
||||
if keyId <= 0 {
|
||||
return errors.New("invalid 'keyId'")
|
||||
}
|
||||
|
||||
if len(nodesJSON) == 0 {
|
||||
nodesJSON = []byte("{}")
|
||||
}
|
||||
|
||||
taskId, err := this.Query(tx).
|
||||
Pk(keyId).
|
||||
Result("taskId").
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var jsonPath = "$.\"" + types.String(nodeId) + "\""
|
||||
|
||||
var query = this.Query(tx).
|
||||
Pk(keyId).
|
||||
Set("nodes", dbs.SQL("JSON_SET(nodes, :jsonPath1, true)")).
|
||||
Param("jsonPath1", jsonPath)
|
||||
|
||||
if len(errString) > 0 {
|
||||
query.Set("errors", dbs.SQL("JSON_SET(errors, :jsonPath2, :jsonValue2)")).
|
||||
Param("jsonPath2", jsonPath).
|
||||
Param("jsonValue2", errString)
|
||||
} else {
|
||||
query.Set("errors", dbs.SQL("JSON_REMOVE(errors, :jsonPath2)")).
|
||||
Param("jsonPath2", jsonPath)
|
||||
}
|
||||
|
||||
err = query.
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查是否已完成
|
||||
isDone, err := this.Query(tx).
|
||||
Pk(keyId).
|
||||
Where("JSON_CONTAINS(nodes, :nodesJSON)").
|
||||
Param("nodesJSON", nodesJSON).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isDone {
|
||||
err = this.Query(tx).
|
||||
Pk(keyId).
|
||||
Set("isDone", isDone).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查任务是否已经完成
|
||||
taskIsNotDone, err := this.Query(tx).
|
||||
Attr("taskId", taskId).
|
||||
Attr("isDone", false).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var taskIsDone = !taskIsNotDone
|
||||
var hasErrors = true
|
||||
if taskIsDone {
|
||||
// 已经完成,是否有错误
|
||||
hasErrors, err = this.Query(tx).
|
||||
Attr("taskId", taskId).
|
||||
Where("JSON_LENGTH(errors)>0").
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = SharedHTTPCacheTaskDAO.UpdateTaskStatus(tx, taskId, taskIsDone, !hasErrors)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindAllTaskKeys 查询某个任务下的所有Key
|
||||
func (this *HTTPCacheTaskKeyDAO) FindAllTaskKeys(tx *dbs.Tx, taskId int64) (result []*HTTPCacheTaskKey, err error) {
|
||||
_, err = this.Query(tx).
|
||||
Attr("taskId", taskId).
|
||||
AscPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindDoingTaskKeys 查询要执行的任务
|
||||
func (this *HTTPCacheTaskKeyDAO) FindDoingTaskKeys(tx *dbs.Tx, nodeId int64, size int64) (result []*HTTPCacheTaskKey, err error) {
|
||||
// 集群ID
|
||||
clusterIds, err := SharedNodeDAO.FindEnabledAndOnNodeClusterIds(tx, nodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(clusterIds) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Attr("clusterId", clusterIds).
|
||||
Attr("isDone", false).
|
||||
Where("NOT JSON_CONTAINS_PATH(nodes, 'one', :jsonPath1)").
|
||||
Param("jsonPath1", "$.\""+types.String(nodeId)+"\"").
|
||||
Where("taskId IN (SELECT id FROM " + SharedHTTPCacheTaskDAO.Table + " WHERE state=1 AND isReady=1 AND isDone=0)").
|
||||
Limit(size).
|
||||
AscPk().
|
||||
Reuse(false).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ResetCacheKeysWithTaskId 重置任务下的Key状态
|
||||
func (this *HTTPCacheTaskKeyDAO) ResetCacheKeysWithTaskId(tx *dbs.Tx, taskId int64) error {
|
||||
return this.Query(tx).
|
||||
Attr("taskId", taskId).
|
||||
Set("isDone", false).
|
||||
Set("nodes", "{}").
|
||||
Set("errors", "{}").
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// CountUserTasksInDay 读取某个用户当前数量
|
||||
// day YYYYMMDD
|
||||
func (this *HTTPCacheTaskKeyDAO) CountUserTasksInDay(tx *dbs.Tx, userId int64, day string, taskType HTTPCacheTaskType) (int64, error) {
|
||||
if userId <= 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 这里需要包含已删除的
|
||||
return this.Query(tx).
|
||||
Where("taskId IN (SELECT id FROM "+SharedHTTPCacheTaskDAO.Table+" WHERE userId=:userId AND day=:day AND type=:type)").
|
||||
Param("userId", userId).
|
||||
Param("day", day).
|
||||
Param("type", taskType).
|
||||
Count()
|
||||
}
|
||||
|
||||
// Clean 清理以往的任务
|
||||
func (this *HTTPCacheTaskKeyDAO) Clean(tx *dbs.Tx, days int) error {
|
||||
if days <= 0 {
|
||||
days = 30
|
||||
}
|
||||
|
||||
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
|
||||
_, err := this.Query(tx).
|
||||
Where("taskId IN (SELECT id FROM "+SharedHTTPCacheTaskDAO.Table+" WHERE day<=:day)").
|
||||
Param("day", day).
|
||||
Delete()
|
||||
return err
|
||||
}
|
||||
54
internal/db/models/http_cache_task_key_dao_test.go
Normal file
54
internal/db/models/http_cache_task_key_dao_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHTTPCacheTaskKeyDAO_CreateKey(t *testing.T) {
|
||||
var dao = models.NewHTTPCacheTaskKeyDAO()
|
||||
var tx *dbs.Tx
|
||||
_, err := dao.CreateKey(tx, 1, "a", "purge", "key", 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestHTTPCacheTaskKeyDAO_UpdateKeyStatus(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var dao = models.NewHTTPCacheTaskKeyDAO()
|
||||
var tx *dbs.Tx
|
||||
var errString = "" // "this is error"
|
||||
err := dao.UpdateKeyStatus(tx, 3, 1, errString, []byte(`{"1":true}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestHTTPCacheTaskKeyDAO_CountUserTasksInDay(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var dao = models.NewHTTPCacheTaskKeyDAO()
|
||||
var tx *dbs.Tx
|
||||
{
|
||||
count, err := dao.CountUserTasksInDay(tx, 1, timeutil.Format("Ymd"), models.HTTPCacheTaskTypePurge)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("count:", count)
|
||||
}
|
||||
{
|
||||
count, err := dao.CountUserTasksInDay(tx, 1, timeutil.Format("Ymd"), models.HTTPCacheTaskTypeFetch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("count:", count)
|
||||
}
|
||||
}
|
||||
32
internal/db/models/http_cache_task_key_model.go
Normal file
32
internal/db/models/http_cache_task_key_model.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package models
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// HTTPCacheTaskKey 缓存任务Key
|
||||
type HTTPCacheTaskKey struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
TaskId uint64 `field:"taskId"` // 任务ID
|
||||
Key string `field:"key"` // Key
|
||||
KeyType string `field:"keyType"` // Key类型:key|prefix
|
||||
Type string `field:"type"` // 操作类型
|
||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||
Nodes dbs.JSON `field:"nodes"` // 节点
|
||||
Errors dbs.JSON `field:"errors"` // 错误信息
|
||||
IsDone bool `field:"isDone"` // 是否已完成
|
||||
}
|
||||
|
||||
type HTTPCacheTaskKeyOperator struct {
|
||||
Id interface{} // ID
|
||||
TaskId interface{} // 任务ID
|
||||
Key interface{} // Key
|
||||
KeyType interface{} // Key类型:key|prefix
|
||||
Type interface{} // 操作类型
|
||||
ClusterId interface{} // 集群ID
|
||||
Nodes interface{} // 节点
|
||||
Errors interface{} // 错误信息
|
||||
IsDone interface{} // 是否已完成
|
||||
}
|
||||
|
||||
func NewHTTPCacheTaskKeyOperator() *HTTPCacheTaskKeyOperator {
|
||||
return &HTTPCacheTaskKeyOperator{}
|
||||
}
|
||||
20
internal/db/models/http_cache_task_key_model_ext.go
Normal file
20
internal/db/models/http_cache_task_key_model_ext.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package models
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// DecodeNodes 解析已完成节点信息
|
||||
func (this *HTTPCacheTaskKey) DecodeNodes() map[string]bool {
|
||||
var result = map[string]bool{}
|
||||
var nodesJSON = this.Nodes
|
||||
if IsNull(nodesJSON) {
|
||||
return result
|
||||
}
|
||||
|
||||
err := json.Unmarshal(nodesJSON, &result)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
return result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
36
internal/db/models/http_cache_task_model.go
Normal file
36
internal/db/models/http_cache_task_model.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package models
|
||||
|
||||
// HTTPCacheTask 缓存相关任务
|
||||
type HTTPCacheTask struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
Type string `field:"type"` // 任务类型:purge|fetch
|
||||
KeyType string `field:"keyType"` // Key类型
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
DoneAt uint64 `field:"doneAt"` // 完成时间
|
||||
Day string `field:"day"` // 创建日期YYYYMMDD
|
||||
IsDone bool `field:"isDone"` // 是否已完成
|
||||
IsOk bool `field:"isOk"` // 是否完全成功
|
||||
IsReady uint8 `field:"isReady"` // 是否已准备好
|
||||
Description string `field:"description"` // 描述
|
||||
}
|
||||
|
||||
type HTTPCacheTaskOperator struct {
|
||||
Id interface{} // ID
|
||||
UserId interface{} // 用户ID
|
||||
Type interface{} // 任务类型:purge|fetch
|
||||
KeyType interface{} // Key类型
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
DoneAt interface{} // 完成时间
|
||||
Day interface{} // 创建日期YYYYMMDD
|
||||
IsDone interface{} // 是否已完成
|
||||
IsOk interface{} // 是否完全成功
|
||||
IsReady interface{} // 是否已准备好
|
||||
Description interface{} // 描述
|
||||
}
|
||||
|
||||
func NewHTTPCacheTaskOperator() *HTTPCacheTaskOperator {
|
||||
return &HTTPCacheTaskOperator{}
|
||||
}
|
||||
1
internal/db/models/http_cache_task_model_ext.go
Normal file
1
internal/db/models/http_cache_task_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package models
|
||||
@@ -117,7 +117,7 @@ func (this *HTTPFirewallPolicyDAO) FindAllEnabledFirewallPolicies(tx *dbs.Tx) (r
|
||||
|
||||
// CreateFirewallPolicy 创建策略
|
||||
func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64, serverGroupId int64, serverId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte) (int64, error) {
|
||||
op := NewHTTPFirewallPolicyOperator()
|
||||
var op = NewHTTPFirewallPolicyOperator()
|
||||
op.UserId = userId
|
||||
op.GroupId = serverGroupId
|
||||
op.ServerId = serverId
|
||||
@@ -131,14 +131,31 @@ func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64
|
||||
if len(outboundJSON) > 0 {
|
||||
op.Outbound = outboundJSON
|
||||
}
|
||||
op.UseLocalFirewall = true
|
||||
|
||||
{
|
||||
synFloodJSON, err := json.Marshal(firewallconfigs.DefaultSYNFloodConfig())
|
||||
if userId <= 0 && serverGroupId <=0 && serverId <= 0 {
|
||||
// synFlood
|
||||
var synFloodConfig = firewallconfigs.DefaultSYNFloodConfig()
|
||||
synFloodJSON, err := json.Marshal(synFloodConfig)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.SynFlood = synFloodJSON
|
||||
|
||||
// block options
|
||||
var blockOptions = firewallconfigs.DefaultHTTPFirewallBlockAction()
|
||||
blockOptionsJSON, err := json.Marshal(blockOptions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.BlockOptions = blockOptionsJSON
|
||||
|
||||
// captcha options
|
||||
var captchaOptions = firewallconfigs.DefaultHTTPFirewallCaptchaAction()
|
||||
captchaOptionsJSON, err := json.Marshal(captchaOptions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.CaptchaOptions = captchaOptionsJSON
|
||||
}
|
||||
|
||||
err := this.Save(tx, op)
|
||||
@@ -160,8 +177,8 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
|
||||
groupCodes = append(groupCodes, group.Code)
|
||||
}
|
||||
|
||||
inboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||
outboundConfig := &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
|
||||
var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||
var outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
|
||||
if templatePolicy.Inbound != nil {
|
||||
for _, group := range templatePolicy.Inbound.Groups {
|
||||
isOn := lists.ContainsString(groupCodes, group.Code)
|
||||
@@ -207,6 +224,7 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return policyId, nil
|
||||
}
|
||||
|
||||
@@ -268,6 +286,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
|
||||
inboundJSON []byte,
|
||||
outboundJSON []byte,
|
||||
blockOptionsJSON []byte,
|
||||
captchaOptionsJSON []byte,
|
||||
mode firewallconfigs.FirewallMode,
|
||||
useLocalFirewall bool,
|
||||
synFloodConfig *firewallconfigs.SYNFloodConfig,
|
||||
@@ -275,7 +294,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
op := NewHTTPFirewallPolicyOperator()
|
||||
var op = NewHTTPFirewallPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
@@ -291,9 +310,12 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
|
||||
} else {
|
||||
op.Outbound = "null"
|
||||
}
|
||||
if len(blockOptionsJSON) > 0 {
|
||||
if IsNotNull(blockOptionsJSON) {
|
||||
op.BlockOptions = blockOptionsJSON
|
||||
}
|
||||
if IsNotNull(captchaOptionsJSON) {
|
||||
op.CaptchaOptions = captchaOptionsJSON
|
||||
}
|
||||
|
||||
if synFloodConfig != nil {
|
||||
synFloodConfigJSON, err := json.Marshal(synFloodConfig)
|
||||
@@ -456,7 +478,7 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
|
||||
|
||||
// Block动作配置
|
||||
if IsNotNull(policy.BlockOptions) {
|
||||
blockAction := &firewallconfigs.HTTPFirewallBlockAction{}
|
||||
var blockAction = &firewallconfigs.HTTPFirewallBlockAction{}
|
||||
err = json.Unmarshal(policy.BlockOptions, blockAction)
|
||||
if err != nil {
|
||||
return config, err
|
||||
@@ -464,6 +486,16 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
|
||||
config.BlockOptions = blockAction
|
||||
}
|
||||
|
||||
// Captcha动作配置
|
||||
if IsNotNull(policy.CaptchaOptions) {
|
||||
var captchaAction = &firewallconfigs.HTTPFirewallCaptchaAction{}
|
||||
err = json.Unmarshal(policy.CaptchaOptions, captchaAction)
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
config.CaptchaOptions = captchaAction
|
||||
}
|
||||
|
||||
// syn flood
|
||||
if IsNotNull(policy.SynFlood) {
|
||||
var synFloodConfig = &firewallconfigs.SYNFloodConfig{}
|
||||
@@ -526,6 +558,7 @@ func (this *HTTPFirewallPolicyDAO) CheckUserFirewallPolicy(tx *dbs.Tx, userId in
|
||||
}
|
||||
|
||||
// FindEnabledFirewallPolicyIdsWithIPListId 查找包含某个IPList的所有策略
|
||||
// TODO 改成通过 serverId 查询
|
||||
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *dbs.Tx, ipListId int64) ([]int64, error) {
|
||||
ones, err := this.Query(tx).
|
||||
ResultPk().
|
||||
@@ -544,6 +577,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *
|
||||
}
|
||||
|
||||
// FindEnabledFirewallPolicyWithIPListId 查找使用某个IPList的策略
|
||||
// TODO 改成通过 serverId 查询
|
||||
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyWithIPListId(tx *dbs.Tx, ipListId int64) (*HTTPFirewallPolicy, error) {
|
||||
one, err := this.Query(tx).
|
||||
State(HTTPFirewallPolicyStateEnabled).
|
||||
|
||||
@@ -18,6 +18,7 @@ type HTTPFirewallPolicy struct {
|
||||
Inbound dbs.JSON `field:"inbound"` // 入站规则
|
||||
Outbound dbs.JSON `field:"outbound"` // 出站规则
|
||||
BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项
|
||||
CaptchaOptions dbs.JSON `field:"captchaOptions"` // 验证码选项
|
||||
Mode string `field:"mode"` // 模式
|
||||
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
|
||||
SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置
|
||||
@@ -39,6 +40,7 @@ type HTTPFirewallPolicyOperator struct {
|
||||
Inbound interface{} // 入站规则
|
||||
Outbound interface{} // 出站规则
|
||||
BlockOptions interface{} // BLOCK选项
|
||||
CaptchaOptions interface{} // 验证码选项
|
||||
Mode interface{} // 模式
|
||||
UseLocalFirewall interface{} // 是否自动使用本地防火墙
|
||||
SynFlood interface{} // SynFlood防御设置
|
||||
|
||||
@@ -3,6 +3,7 @@ package models
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
@@ -446,6 +447,16 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
|
||||
}
|
||||
}
|
||||
|
||||
// UAM
|
||||
if teaconst.IsPlus && IsNotNull(web.Uam) {
|
||||
var uamConfig = &serverconfigs.UAMConfig{}
|
||||
err = json.Unmarshal(web.Uam, uamConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.UAM = uamConfig
|
||||
}
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, config)
|
||||
}
|
||||
@@ -1168,6 +1179,35 @@ func (this *HTTPWebDAO) FindWebRequestScripts(tx *dbs.Tx, webId int64) (*serverc
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// UpdateWebUAM 开启UAM
|
||||
func (this *HTTPWebDAO) UpdateWebUAM(tx *dbs.Tx, webId int64, uamConfig *serverconfigs.UAMConfig) error {
|
||||
if uamConfig == nil {
|
||||
return nil
|
||||
}
|
||||
configJSON, err := json.Marshal(uamConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = this.Query(tx).
|
||||
Pk(webId).
|
||||
Set("uam", configJSON).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return this.NotifyUpdate(tx, webId)
|
||||
}
|
||||
|
||||
// FindWebUAM 查找服务的UAM配置
|
||||
func (this *HTTPWebDAO) FindWebUAM(tx *dbs.Tx, webId int64) ([]byte, error) {
|
||||
return this.Query(tx).
|
||||
Pk(webId).
|
||||
Result("uam").
|
||||
FindJSONCol()
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *HTTPWebDAO) NotifyUpdate(tx *dbs.Tx, webId int64) error {
|
||||
// server
|
||||
|
||||
@@ -37,6 +37,7 @@ type HTTPWeb struct {
|
||||
MergeSlashes uint8 `field:"mergeSlashes"` // 是否合并路径中的斜杠
|
||||
RequestLimit dbs.JSON `field:"requestLimit"` // 请求限制
|
||||
RequestScripts dbs.JSON `field:"requestScripts"` // 请求脚本
|
||||
Uam dbs.JSON `field:"uam"` // UAM设置
|
||||
}
|
||||
|
||||
type HTTPWebOperator struct {
|
||||
@@ -73,6 +74,7 @@ type HTTPWebOperator struct {
|
||||
MergeSlashes interface{} // 是否合并路径中的斜杠
|
||||
RequestLimit interface{} // 请求限制
|
||||
RequestScripts interface{} // 请求脚本
|
||||
Uam interface{} // UAM设置
|
||||
}
|
||||
|
||||
func NewHTTPWebOperator() *HTTPWebOperator {
|
||||
|
||||
@@ -93,6 +93,71 @@ func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error {
|
||||
return this.NotifyUpdate(tx, id)
|
||||
}
|
||||
|
||||
// DisableIPItemsWithIP 禁用某个IP相关条目
|
||||
func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo string, userId int64, listId int64) error {
|
||||
if len(ipFrom) == 0 {
|
||||
return errors.New("invalid 'ipFrom'")
|
||||
}
|
||||
|
||||
var query = this.Query(tx).
|
||||
Result("id", "listId").
|
||||
Attr("ipFrom", ipFrom).
|
||||
Attr("ipTo", ipTo).
|
||||
State(IPItemStateEnabled)
|
||||
|
||||
if listId > 0 {
|
||||
if userId > 0 {
|
||||
err := SharedIPListDAO.CheckUserIPList(tx, userId, listId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
query.Attr("listId", listId)
|
||||
}
|
||||
|
||||
ones, err := query.FindAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var itemIds = []int64{}
|
||||
for _, one := range ones {
|
||||
var item = one.(*IPItem)
|
||||
var itemId = int64(item.Id)
|
||||
var itemListId = int64(item.ListId)
|
||||
if itemListId != listId && userId > 0 {
|
||||
err = SharedIPListDAO.CheckUserIPList(tx, userId, itemListId)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
continue
|
||||
}
|
||||
}
|
||||
itemIds = append(itemIds, itemId)
|
||||
}
|
||||
|
||||
for _, itemId := range itemIds {
|
||||
version, err := SharedIPListDAO.IncreaseVersion(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Pk(itemId).
|
||||
Set("state", IPItemStateDisabled).
|
||||
Set("version", version).
|
||||
Update()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(itemIds) > 0 {
|
||||
return this.NotifyUpdate(tx, itemIds[len(itemIds)-1])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisableIPItemsWithListId 禁用某个IP名单内的所有IP
|
||||
func (this *IPItemDAO) DisableIPItemsWithListId(tx *dbs.Tx, listId int64) error {
|
||||
for {
|
||||
@@ -453,7 +518,7 @@ func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx) error {
|
||||
func (this *IPItemDAO) CleanExpiredIPItems(tx *dbs.Tx) error {
|
||||
// 删除 N 天之前过期的数据
|
||||
_, err := this.Query(tx).
|
||||
Where("expiredAt<=:timestamp").
|
||||
Where("(createdAt<=:timestamp AND updatedAt<=:timestamp)").
|
||||
State(IPItemStateDisabled).
|
||||
Param("timestamp", time.Now().Unix()-7*86400). // N 天之前过期的
|
||||
Limit(10000). // 限制条数,防止数量过多导致超时
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package models
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
@@ -14,7 +15,7 @@ func TestIPItemDAO_NotifyClustersUpdate(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := SharedIPItemDAO.NotifyUpdate(tx, 28)
|
||||
err := models.SharedIPItemDAO.NotifyUpdate(tx, 28)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -25,7 +26,7 @@ func TestIPItemDAO_DisableIPItemsWithListId(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := SharedIPItemDAO.DisableIPItemsWithListId(tx, 67)
|
||||
err := models.SharedIPItemDAO.DisableIPItemsWithListId(tx, 67)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -36,7 +37,7 @@ func TestIPItemDAO_ListIPItemsAfterVersion(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
_, err := SharedIPItemDAO.ListIPItemsAfterVersion(tx, 0, 100)
|
||||
_, err := models.SharedIPItemDAO.ListIPItemsAfterVersion(tx, 0, 100)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -47,10 +48,10 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
var dao = NewIPItemDAO()
|
||||
var dao = models.NewIPItemDAO()
|
||||
var n = 10
|
||||
for i := 0; i < n; i++ {
|
||||
itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0)
|
||||
itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", models.IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -62,3 +63,14 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestIPItemDAO_DisableIPItemsWithIP(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := models.SharedIPItemDAO.DisableIPItemsWithIP(tx, "192.168.1.100", "", 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
@@ -138,10 +138,11 @@ func (this *IPListDAO) FindIPListCacheable(tx *dbs.Tx, listId int64) (*IPList, e
|
||||
}
|
||||
|
||||
// CreateIPList 创建名单
|
||||
func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, listType ipconfigs.IPListType, name string, code string, timeoutJSON []byte, description string, isPublic bool, isGlobal bool) (int64, error) {
|
||||
op := NewIPListOperator()
|
||||
func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, serverId int64, listType ipconfigs.IPListType, name string, code string, timeoutJSON []byte, description string, isPublic bool, isGlobal bool) (int64, error) {
|
||||
var op = NewIPListOperator()
|
||||
op.IsOn = true
|
||||
op.UserId = userId
|
||||
op.ServerId = serverId
|
||||
op.State = IPListStateEnabled
|
||||
op.Type = listType
|
||||
op.Name = name
|
||||
@@ -189,26 +190,25 @@ func (this *IPListDAO) CheckUserIPList(tx *dbs.Tx, userId int64, listId int64) e
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
ok, err := this.Query(tx).
|
||||
// 获取名单信息
|
||||
listOne, err := this.Query(tx).
|
||||
Pk(listId).
|
||||
Attr("userId", userId).
|
||||
Exist()
|
||||
Result("userId", "serverId").
|
||||
Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
if listOne == nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
var list = listOne.(*IPList)
|
||||
if int64(list.UserId) == userId {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查是否被用户的服务所使用
|
||||
policyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, policyId := range policyIds {
|
||||
if SharedHTTPFirewallPolicyDAO.CheckUserFirewallPolicy(tx, userId, policyId) == nil {
|
||||
return nil
|
||||
}
|
||||
var serverId = int64(list.ServerId)
|
||||
if serverId > 0 {
|
||||
return SharedServerDAO.CheckUserServer(tx, userId, serverId)
|
||||
}
|
||||
|
||||
return ErrNotFound
|
||||
|
||||
@@ -20,6 +20,39 @@ func TestIPListDAO_IncreaseVersion(t *testing.T) {
|
||||
t.Log("version:", version)
|
||||
}
|
||||
|
||||
func TestIPListDAO_CheckUserIPList(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
|
||||
{
|
||||
err := NewIPListDAO().CheckUserIPList(tx, 1, 100)
|
||||
if err == ErrNotFound {
|
||||
t.Log("not found")
|
||||
} else {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
err := NewIPListDAO().CheckUserIPList(tx, 1, 85)
|
||||
if err == ErrNotFound {
|
||||
t.Log("not found")
|
||||
} else {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
err := NewIPListDAO().CheckUserIPList(tx, 1, 17)
|
||||
if err == ErrNotFound {
|
||||
t.Log("not found")
|
||||
} else {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
|
||||
runtime.GOMAXPROCS(1)
|
||||
|
||||
@@ -32,3 +65,4 @@ func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
|
||||
_, _ = dao.IncreaseVersion(tx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ type IPList struct {
|
||||
Type string `field:"type"` // 类型
|
||||
AdminId uint32 `field:"adminId"` // 用户ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
ServerId uint64 `field:"serverId"` // 服务ID
|
||||
Name string `field:"name"` // 列表名
|
||||
Code string `field:"code"` // 代号
|
||||
State uint8 `field:"state"` // 状态
|
||||
@@ -26,6 +27,7 @@ type IPListOperator struct {
|
||||
Type interface{} // 类型
|
||||
AdminId interface{} // 用户ID
|
||||
UserId interface{} // 用户ID
|
||||
ServerId interface{} // 服务ID
|
||||
Name interface{} // 列表名
|
||||
Code interface{} // 代号
|
||||
State interface{} // 状态
|
||||
|
||||
@@ -90,9 +90,7 @@ func (this *MetricStatDAO) CreateStat(tx *dbs.Tx, hash string, clusterId int64,
|
||||
"value": value,
|
||||
})
|
||||
if err != nil {
|
||||
// 忽略 Error 1213: Deadlock found 错误
|
||||
mysqlErr, ok := err.(*mysql.MySQLError)
|
||||
if ok && mysqlErr.Number == 1213 {
|
||||
if this.canIgnore(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -135,6 +133,9 @@ func (this *MetricStatDAO) DeleteNodeItemStats(tx *dbs.Tx, nodeId int64, serverI
|
||||
Attr("itemId", itemId).
|
||||
Attr("time", time).
|
||||
Delete()
|
||||
if this.canIgnore(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -751,3 +752,18 @@ func (this *MetricStatDAO) mergeStats(stats []*MetricStat) (result []*MetricStat
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 检查错误是否可以忽略
|
||||
func (this *MetricStatDAO) canIgnore(err error) bool {
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// 忽略 Error 1213: Deadlock found 错误
|
||||
mysqlErr, ok := err.(*mysql.MySQLError)
|
||||
if ok && mysqlErr.Number == 1213 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
@@ -55,7 +56,7 @@ func init() {
|
||||
|
||||
// UpdateSum 更新统计数据
|
||||
func (this *MetricSumStatDAO) UpdateSum(tx *dbs.Tx, clusterId int64, nodeId int64, serverId int64, time string, itemId int64, version int32, count int64, total float32) error {
|
||||
return this.Query(tx).
|
||||
err := this.Query(tx).
|
||||
Table(this.partialTable(serverId)).
|
||||
InsertOrUpdateQuickly(maps.Map{
|
||||
"clusterId": clusterId,
|
||||
@@ -71,6 +72,10 @@ func (this *MetricSumStatDAO) UpdateSum(tx *dbs.Tx, clusterId int64, nodeId int6
|
||||
"count": count,
|
||||
"total": total,
|
||||
})
|
||||
if this.canIgnore(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// FindNodeServerSum 查找某个服务在某个节点上的统计数据
|
||||
@@ -277,3 +282,18 @@ func (this *MetricSumStatDAO) runBatch(f func(table string, locker *sync.Mutex)
|
||||
wg.Wait()
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// 检查错误是否可以忽略
|
||||
func (this *MetricSumStatDAO) canIgnore(err error) bool {
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// 忽略 Error 1213: Deadlock found 错误
|
||||
mysqlErr, ok := err.(*mysql.MySQLError)
|
||||
if ok && mysqlErr.Number == 1213 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
@@ -180,7 +181,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
|
||||
}
|
||||
|
||||
// UpdateCluster 修改集群
|
||||
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, nodeTCPMaxConnections int32, autoOpenPorts bool) error {
|
||||
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, autoOpenPorts bool) error {
|
||||
if clusterId <= 0 {
|
||||
return errors.New("invalid clusterId")
|
||||
}
|
||||
@@ -195,11 +196,6 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
|
||||
nodeMaxThreads = 0
|
||||
}
|
||||
op.NodeMaxThreads = nodeMaxThreads
|
||||
|
||||
if nodeTCPMaxConnections < 0 {
|
||||
nodeTCPMaxConnections = 0
|
||||
}
|
||||
op.NodeTCPMaxConnections = nodeTCPMaxConnections
|
||||
op.AutoOpenPorts = autoOpenPorts
|
||||
|
||||
err := this.Save(tx, op)
|
||||
@@ -922,7 +918,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
|
||||
cluster, err := this.Query(tx).
|
||||
Pk(clusterId).
|
||||
State(NodeClusterStateEnabled).
|
||||
Result("timeZone", "nodeMaxThreads", "nodeTCPMaxConnections", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "isOn").
|
||||
Result("id", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "isOn", "ddosProtection").
|
||||
Find()
|
||||
if err != nil || cluster == nil {
|
||||
return nil, err
|
||||
@@ -992,6 +988,45 @@ func (this *NodeClusterDAO) FindClusterWebPPolicy(tx *dbs.Tx, clusterId int64, c
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
// FindClusterDDoSProtection 获取集群的DDoS设置
|
||||
func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) {
|
||||
one, err := this.Query(tx).
|
||||
Result("ddosProtection").
|
||||
Pk(clusterId).
|
||||
Find()
|
||||
if one == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*NodeCluster).DecodeDDoSProtection(), nil
|
||||
}
|
||||
|
||||
// UpdateClusterDDoSProtection 设置集群的DDOS设置
|
||||
func (this *NodeClusterDAO) UpdateClusterDDoSProtection(tx *dbs.Tx, clusterId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
|
||||
if clusterId <= 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
var op = NewNodeClusterOperator()
|
||||
op.Id = clusterId
|
||||
|
||||
if ddosProtection == nil {
|
||||
op.DdosProtection = "{}"
|
||||
} else {
|
||||
ddosProtectionJSON, err := json.Marshal(ddosProtection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.DdosProtection = ddosProtectionJSON
|
||||
}
|
||||
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeDDosProtectionChanged)
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *NodeClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged)
|
||||
|
||||
@@ -4,69 +4,69 @@ import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// NodeCluster 节点集群
|
||||
type NodeCluster struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 名称
|
||||
UseAllAPINodes uint8 `field:"useAllAPINodes"` // 是否使用所有API节点
|
||||
ApiNodes dbs.JSON `field:"apiNodes"` // 使用的API节点
|
||||
InstallDir string `field:"installDir"` // 安装目录
|
||||
Order uint32 `field:"order"` // 排序
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
GrantId uint32 `field:"grantId"` // 默认认证方式
|
||||
State uint8 `field:"state"` // 状态
|
||||
AutoRegister uint8 `field:"autoRegister"` // 是否开启自动注册
|
||||
UniqueId string `field:"uniqueId"` // 唯一ID
|
||||
Secret string `field:"secret"` // 密钥
|
||||
HealthCheck dbs.JSON `field:"healthCheck"` // 健康检查
|
||||
DnsName string `field:"dnsName"` // DNS名称
|
||||
DnsDomainId uint32 `field:"dnsDomainId"` // 域名ID
|
||||
Dns dbs.JSON `field:"dns"` // DNS配置
|
||||
Toa dbs.JSON `field:"toa"` // TOA配置
|
||||
CachePolicyId uint32 `field:"cachePolicyId"` // 缓存策略ID
|
||||
HttpFirewallPolicyId uint32 `field:"httpFirewallPolicyId"` // WAF策略ID
|
||||
AccessLog dbs.JSON `field:"accessLog"` // 访问日志设置
|
||||
SystemServices dbs.JSON `field:"systemServices"` // 系统服务设置
|
||||
TimeZone string `field:"timeZone"` // 时区
|
||||
NodeMaxThreads uint32 `field:"nodeMaxThreads"` // 节点最大线程数
|
||||
NodeTCPMaxConnections uint32 `field:"nodeTCPMaxConnections"` // TCP最大连接数
|
||||
AutoOpenPorts uint8 `field:"autoOpenPorts"` // 是否自动尝试开放端口
|
||||
IsPinned bool `field:"isPinned"` // 是否置顶
|
||||
Webp dbs.JSON `field:"webp"` // WebP设置
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 名称
|
||||
UseAllAPINodes uint8 `field:"useAllAPINodes"` // 是否使用所有API节点
|
||||
ApiNodes dbs.JSON `field:"apiNodes"` // 使用的API节点
|
||||
InstallDir string `field:"installDir"` // 安装目录
|
||||
Order uint32 `field:"order"` // 排序
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
GrantId uint32 `field:"grantId"` // 默认认证方式
|
||||
State uint8 `field:"state"` // 状态
|
||||
AutoRegister uint8 `field:"autoRegister"` // 是否开启自动注册
|
||||
UniqueId string `field:"uniqueId"` // 唯一ID
|
||||
Secret string `field:"secret"` // 密钥
|
||||
HealthCheck dbs.JSON `field:"healthCheck"` // 健康检查
|
||||
DnsName string `field:"dnsName"` // DNS名称
|
||||
DnsDomainId uint32 `field:"dnsDomainId"` // 域名ID
|
||||
Dns dbs.JSON `field:"dns"` // DNS配置
|
||||
Toa dbs.JSON `field:"toa"` // TOA配置
|
||||
CachePolicyId uint32 `field:"cachePolicyId"` // 缓存策略ID
|
||||
HttpFirewallPolicyId uint32 `field:"httpFirewallPolicyId"` // WAF策略ID
|
||||
AccessLog dbs.JSON `field:"accessLog"` // 访问日志设置
|
||||
SystemServices dbs.JSON `field:"systemServices"` // 系统服务设置
|
||||
TimeZone string `field:"timeZone"` // 时区
|
||||
NodeMaxThreads uint32 `field:"nodeMaxThreads"` // 节点最大线程数
|
||||
DdosProtection dbs.JSON `field:"ddosProtection"` // DDOS端口
|
||||
AutoOpenPorts uint8 `field:"autoOpenPorts"` // 是否自动尝试开放端口
|
||||
IsPinned bool `field:"isPinned"` // 是否置顶
|
||||
Webp dbs.JSON `field:"webp"` // WebP设置
|
||||
}
|
||||
|
||||
type NodeClusterOperator struct {
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 名称
|
||||
UseAllAPINodes interface{} // 是否使用所有API节点
|
||||
ApiNodes interface{} // 使用的API节点
|
||||
InstallDir interface{} // 安装目录
|
||||
Order interface{} // 排序
|
||||
CreatedAt interface{} // 创建时间
|
||||
GrantId interface{} // 默认认证方式
|
||||
State interface{} // 状态
|
||||
AutoRegister interface{} // 是否开启自动注册
|
||||
UniqueId interface{} // 唯一ID
|
||||
Secret interface{} // 密钥
|
||||
HealthCheck interface{} // 健康检查
|
||||
DnsName interface{} // DNS名称
|
||||
DnsDomainId interface{} // 域名ID
|
||||
Dns interface{} // DNS配置
|
||||
Toa interface{} // TOA配置
|
||||
CachePolicyId interface{} // 缓存策略ID
|
||||
HttpFirewallPolicyId interface{} // WAF策略ID
|
||||
AccessLog interface{} // 访问日志设置
|
||||
SystemServices interface{} // 系统服务设置
|
||||
TimeZone interface{} // 时区
|
||||
NodeMaxThreads interface{} // 节点最大线程数
|
||||
NodeTCPMaxConnections interface{} // TCP最大连接数
|
||||
AutoOpenPorts interface{} // 是否自动尝试开放端口
|
||||
IsPinned interface{} // 是否置顶
|
||||
Webp interface{} // WebP设置
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 名称
|
||||
UseAllAPINodes interface{} // 是否使用所有API节点
|
||||
ApiNodes interface{} // 使用的API节点
|
||||
InstallDir interface{} // 安装目录
|
||||
Order interface{} // 排序
|
||||
CreatedAt interface{} // 创建时间
|
||||
GrantId interface{} // 默认认证方式
|
||||
State interface{} // 状态
|
||||
AutoRegister interface{} // 是否开启自动注册
|
||||
UniqueId interface{} // 唯一ID
|
||||
Secret interface{} // 密钥
|
||||
HealthCheck interface{} // 健康检查
|
||||
DnsName interface{} // DNS名称
|
||||
DnsDomainId interface{} // 域名ID
|
||||
Dns interface{} // DNS配置
|
||||
Toa interface{} // TOA配置
|
||||
CachePolicyId interface{} // 缓存策略ID
|
||||
HttpFirewallPolicyId interface{} // WAF策略ID
|
||||
AccessLog interface{} // 访问日志设置
|
||||
SystemServices interface{} // 系统服务设置
|
||||
TimeZone interface{} // 时区
|
||||
NodeMaxThreads interface{} // 节点最大线程数
|
||||
DdosProtection interface{} // DDOS端口
|
||||
AutoOpenPorts interface{} // 是否自动尝试开放端口
|
||||
IsPinned interface{} // 是否置顶
|
||||
Webp interface{} // WebP设置
|
||||
}
|
||||
|
||||
func NewNodeClusterOperator() *NodeClusterOperator {
|
||||
|
||||
@@ -3,6 +3,7 @@ package models
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
)
|
||||
|
||||
// DecodeDNSConfig 解析DNS配置
|
||||
@@ -21,3 +22,26 @@ func (this *NodeCluster) DecodeDNSConfig() (*dnsconfigs.ClusterDNSConfig, error)
|
||||
}
|
||||
return dnsConfig, nil
|
||||
}
|
||||
|
||||
// DecodeDDoSProtection 解析DDOS Protection设置
|
||||
func (this *NodeCluster) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
|
||||
if IsNull(this.DdosProtection) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = &ddosconfigs.ProtectionConfig{}
|
||||
err := json.Unmarshal(this.DdosProtection, &result)
|
||||
if err != nil {
|
||||
// ignore err
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// HasDDoSProtection 检查是否有DDOS设置
|
||||
func (this *NodeCluster) HasDDoSProtection() bool {
|
||||
var config = this.DecodeDDoSProtection()
|
||||
if config != nil {
|
||||
return config.IsOn()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
@@ -360,6 +361,8 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
|
||||
// 分组
|
||||
if groupId > 0 {
|
||||
query.Attr("groupId", groupId)
|
||||
} else if groupId < 0 {
|
||||
query.Attr("groupId", 0)
|
||||
}
|
||||
|
||||
// 区域
|
||||
@@ -567,12 +570,12 @@ func (this *NodeDAO) FindEnabledNodeClusterIds(tx *dbs.Tx, nodeId int64) (result
|
||||
result = append(result, clusterId)
|
||||
}
|
||||
|
||||
for _, clusterId := range one.(*Node).DecodeSecondaryClusterIds() {
|
||||
if lists.ContainsInt64(result, clusterId) {
|
||||
for _, secondaryClusterId := range one.(*Node).DecodeSecondaryClusterIds() {
|
||||
if lists.ContainsInt64(result, secondaryClusterId) {
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, clusterId)
|
||||
result = append(result, secondaryClusterId)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -661,16 +664,51 @@ func (this *NodeDAO) FindAllNodeIdsMatch(tx *dbs.Tx, clusterId int64, includeSec
|
||||
}
|
||||
|
||||
// FindAllEnabledNodesWithClusterId 获取一个集群的所有节点
|
||||
func (this *NodeDAO) FindAllEnabledNodesWithClusterId(tx *dbs.Tx, clusterId int64) (result []*Node, err error) {
|
||||
_, err = this.Query(tx).
|
||||
func (this *NodeDAO) FindAllEnabledNodesWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondary bool) (result []*Node, err error) {
|
||||
var query = this.Query(tx)
|
||||
|
||||
if includeSecondary {
|
||||
query.Where("(clusterId=:primaryClusterId OR JSON_CONTAINS(secondaryClusterIds, :primaryClusterIdString))").
|
||||
Param("primaryClusterId", clusterId).
|
||||
Param("primaryClusterIdString", types.String(clusterId))
|
||||
} else {
|
||||
query.Attr("clusterId", clusterId)
|
||||
}
|
||||
|
||||
_, err = query.
|
||||
State(NodeStateEnabled).
|
||||
Attr("clusterId", clusterId).
|
||||
DescPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindEnabledAndOnNodeIdsWithClusterId 查找某个集群下的所有启用的节点IDs
|
||||
func (this *NodeDAO) FindEnabledAndOnNodeIdsWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondary bool) ([]int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if includeSecondary {
|
||||
query.Where("(clusterId=:primaryClusterId OR JSON_CONTAINS(secondaryClusterIds, :primaryClusterIdString))").
|
||||
Param("primaryClusterId", clusterId).
|
||||
Param("primaryClusterIdString", types.String(clusterId))
|
||||
} else {
|
||||
query.Attr("clusterId", clusterId)
|
||||
}
|
||||
ones, err := query.
|
||||
Attr("isOn", true).
|
||||
State(NodeStateEnabled).
|
||||
ResultPk().
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result = []int64{}
|
||||
for _, one := range ones {
|
||||
result = append(result, int64(one.(*Node).Id))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindAllEnabledNodeIdsWithClusterId 获取一个集群的所有节点Ids
|
||||
func (this *NodeDAO) FindAllEnabledNodeIdsWithClusterId(tx *dbs.Tx, clusterId int64) (result []int64, err error) {
|
||||
ones, err := this.Query(tx).
|
||||
@@ -757,6 +795,8 @@ func (this *NodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx,
|
||||
// 分组
|
||||
if groupId > 0 {
|
||||
query.Attr("groupId", groupId)
|
||||
} else if groupId < 0 {
|
||||
query.Attr("groupId", 0)
|
||||
}
|
||||
|
||||
// 区域
|
||||
@@ -773,11 +813,20 @@ func (this *NodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx,
|
||||
}
|
||||
|
||||
// UpdateNodeStatus 更改节点状态
|
||||
func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
|
||||
_, err := this.Query(tx).
|
||||
func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
|
||||
if nodeStatus == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodeStatusJSON, err := json.Marshal(nodeStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("isActive", true).
|
||||
Set("status", string(statusJSON)).
|
||||
Set("status", nodeStatusJSON).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
@@ -969,6 +1018,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
clusterIds = append(clusterIds, node.DecodeSecondaryClusterIds()...)
|
||||
var clusterIndex = 0
|
||||
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
|
||||
var allowIPMaps = map[string]bool{}
|
||||
for _, clusterId := range clusterIds {
|
||||
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
|
||||
if err != nil {
|
||||
@@ -978,6 +1028,21 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
continue
|
||||
}
|
||||
|
||||
// 节点IP地址
|
||||
nodeIPAddresses, err := SharedNodeIPAddressDAO.FindAllAccessibleIPAddressesWithClusterId(tx, nodeconfigs.NodeRoleNode, clusterId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, address := range nodeIPAddresses {
|
||||
var ip = address.Ip
|
||||
_, ok := allowIPMaps[ip]
|
||||
if !ok {
|
||||
allowIPMaps[ip] = true
|
||||
config.AllowedIPs = append(config.AllowedIPs, ip)
|
||||
}
|
||||
}
|
||||
|
||||
// 防火墙
|
||||
var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId)
|
||||
if httpFirewallPolicyId > 0 {
|
||||
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, cacheMap)
|
||||
@@ -1012,7 +1077,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
// 最大线程数、TCP连接数
|
||||
if clusterIndex == 0 {
|
||||
config.MaxThreads = int(nodeCluster.NodeMaxThreads)
|
||||
config.TCPMaxConnections = int(nodeCluster.NodeTCPMaxConnections)
|
||||
config.DDOSProtection = nodeCluster.DecodeDDoSProtection()
|
||||
config.AutoOpenPorts = nodeCluster.AutoOpenPorts == 1
|
||||
}
|
||||
|
||||
@@ -1070,6 +1135,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
config.SystemServices = services
|
||||
}
|
||||
|
||||
// DNS Resolver
|
||||
if IsNotNull(node.DnsResolver) {
|
||||
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||
err = json.Unmarshal(node.DnsResolver, dnsResolverConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.DNSResolver = dnsResolverConfig
|
||||
}
|
||||
|
||||
// 防火墙动作
|
||||
actions, err := SharedNodeClusterFirewallActionDAO.FindAllEnabledFirewallActions(tx, primaryClusterId, cacheMap)
|
||||
if err != nil {
|
||||
@@ -1134,6 +1209,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
}
|
||||
config.OCSPVersion = ocspVersion
|
||||
|
||||
// DDOS Protection
|
||||
var ddosProtection = node.DecodeDDoSProtection()
|
||||
if ddosProtection != nil {
|
||||
if config.DDOSProtection == nil {
|
||||
config.DDOSProtection = ddosProtection
|
||||
} else {
|
||||
config.DDOSProtection.Merge(ddosProtection)
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化扩展配置
|
||||
err = this.composeExtConfig(tx, config, clusterIds, cacheMap)
|
||||
if err != nil {
|
||||
@@ -1400,6 +1485,49 @@ func (this *NodeDAO) UpdateNodeDNS(tx *dbs.Tx, nodeId int64, routes map[int64][]
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindNodeDNSResolver 查找域名DNS Resolver
|
||||
func (this *NodeDAO) FindNodeDNSResolver(tx *dbs.Tx, nodeId int64) (*nodeconfigs.DNSResolverConfig, error) {
|
||||
configJSON, err := this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Result("dnsResolver").
|
||||
FindJSONCol()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if IsNull(configJSON) {
|
||||
return nodeconfigs.DefaultDNSResolverConfig(), nil
|
||||
}
|
||||
|
||||
var config = nodeconfigs.DefaultDNSResolverConfig()
|
||||
err = json.Unmarshal(configJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// UpdateNodeDNSResolver 修改域名DNS Resolver
|
||||
func (this *NodeDAO) UpdateNodeDNSResolver(tx *dbs.Tx, nodeId int64, dnsResolverConfig *nodeconfigs.DNSResolverConfig) error {
|
||||
if nodeId <= 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(dnsResolverConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var op = NewNodeOperator()
|
||||
op.Id = nodeId
|
||||
op.DnsResolver = configJSON
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return this.NotifyUpdate(tx, nodeId)
|
||||
}
|
||||
|
||||
// UpdateNodeSystem 设置系统信息
|
||||
func (this *NodeDAO) UpdateNodeSystem(tx *dbs.Tx, nodeId int64, maxCPU int32) error {
|
||||
if nodeId <= 0 {
|
||||
@@ -1737,6 +1865,53 @@ func (this *NodeDAO) FindParentNodeConfigs(tx *dbs.Tx, nodeId int64, groupId int
|
||||
return
|
||||
}
|
||||
|
||||
// FindNodeDDoSProtection 获取节点的DDOS设置
|
||||
func (this *NodeDAO) FindNodeDDoSProtection(tx *dbs.Tx, nodeId int64) (*ddosconfigs.ProtectionConfig, error) {
|
||||
one, err := this.Query(tx).
|
||||
Result("ddosProtection").
|
||||
Pk(nodeId).
|
||||
Find()
|
||||
if one == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*Node).DecodeDDoSProtection(), nil
|
||||
}
|
||||
|
||||
// UpdateNodeDDoSProtection 设置集群的DDOS设置
|
||||
func (this *NodeDAO) UpdateNodeDDoSProtection(tx *dbs.Tx, nodeId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
|
||||
if nodeId <= 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
var op = NewNodeOperator()
|
||||
op.Id = nodeId
|
||||
|
||||
if ddosProtection == nil {
|
||||
op.DdosProtection = "{}"
|
||||
} else {
|
||||
ddosProtectionJSON, err := json.Marshal(ddosProtection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.DdosProtection = ddosProtectionJSON
|
||||
}
|
||||
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clusterId, err := this.FindNodeClusterId(tx, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if clusterId > 0 {
|
||||
return SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, 0, NodeTaskTypeDDosProtectionChanged, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知节点相关更新
|
||||
func (this *NodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
||||
// 这里只需要通知单个集群即可,因为节点是公用的,更新一个就相当于更新了所有
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
@@ -375,7 +376,15 @@ func (this *NodeIPAddressDAO) ListEnabledIPAddresses(tx *dbs.Tx, role string, no
|
||||
}
|
||||
|
||||
// FindAllAccessibleIPAddressesWithClusterId 列出所有的正在启用的IP地址
|
||||
func (this *NodeIPAddressDAO) FindAllAccessibleIPAddressesWithClusterId(tx *dbs.Tx, role string, clusterId int64) (result []*NodeIPAddress, err error) {
|
||||
func (this *NodeIPAddressDAO) FindAllAccessibleIPAddressesWithClusterId(tx *dbs.Tx, role string, clusterId int64, cacheMap *utils.CacheMap) (result []*NodeIPAddress, err error) {
|
||||
var cacheKey = this.Table + ":FindAllAccessibleIPAddressesWithClusterId:" + role + ":" + types.String(clusterId)
|
||||
if cacheMap != nil {
|
||||
cache, ok := cacheMap.Get(cacheKey)
|
||||
if ok {
|
||||
return cache.([]*NodeIPAddress), nil
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
State(NodeIPAddressStateEnabled).
|
||||
Attr("role", role).
|
||||
@@ -385,6 +394,14 @@ func (this *NodeIPAddressDAO) FindAllAccessibleIPAddressesWithClusterId(tx *dbs.
|
||||
Param("clusterId", clusterId).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, result)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -31,10 +31,13 @@ type Node struct {
|
||||
State uint8 `field:"state"` // 状态
|
||||
ConnectedAPINodes dbs.JSON `field:"connectedAPINodes"` // 当前连接的API节点
|
||||
MaxCPU uint32 `field:"maxCPU"` // 可以使用的最多CPU
|
||||
MaxThreads uint32 `field:"maxThreads"` // 最大线程数
|
||||
DdosProtection dbs.JSON `field:"ddosProtection"` // DDOS配置
|
||||
DnsRoutes dbs.JSON `field:"dnsRoutes"` // DNS线路设置
|
||||
MaxCacheDiskCapacity dbs.JSON `field:"maxCacheDiskCapacity"` // 硬盘缓存容量
|
||||
MaxCacheMemoryCapacity dbs.JSON `field:"maxCacheMemoryCapacity"` // 内存缓存容量
|
||||
CacheDiskDir string `field:"cacheDiskDir"` // 缓存目录
|
||||
DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器
|
||||
}
|
||||
|
||||
type NodeOperator struct {
|
||||
@@ -65,10 +68,13 @@ type NodeOperator struct {
|
||||
State interface{} // 状态
|
||||
ConnectedAPINodes interface{} // 当前连接的API节点
|
||||
MaxCPU interface{} // 可以使用的最多CPU
|
||||
MaxThreads interface{} // 最大线程数
|
||||
DdosProtection interface{} // DDOS配置
|
||||
DnsRoutes interface{} // DNS线路设置
|
||||
MaxCacheDiskCapacity interface{} // 硬盘缓存容量
|
||||
MaxCacheMemoryCapacity interface{} // 内存缓存容量
|
||||
CacheDiskDir interface{} // 缓存目录
|
||||
DnsResolver interface{} // DNS解析器
|
||||
}
|
||||
|
||||
func NewNodeOperator() *NodeOperator {
|
||||
|
||||
@@ -3,6 +3,8 @@ package models
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
@@ -97,6 +99,7 @@ func (this *Node) DecodeSecondaryClusterIds() []int64 {
|
||||
return result
|
||||
}
|
||||
|
||||
// AllClusterIds 获取所属集群IDs
|
||||
func (this *Node) AllClusterIds() []int64 {
|
||||
var result = []int64{}
|
||||
|
||||
@@ -108,3 +111,60 @@ func (this *Node) AllClusterIds() []int64 {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// DecodeDDoSProtection 解析DDoS Protection设置
|
||||
func (this *Node) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
|
||||
if IsNull(this.DdosProtection) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = &ddosconfigs.ProtectionConfig{}
|
||||
err := json.Unmarshal(this.DdosProtection, &result)
|
||||
if err != nil {
|
||||
// ignore err
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// HasDDoSProtection 检查是否有DDOS设置
|
||||
func (this *Node) HasDDoSProtection() bool {
|
||||
var config = this.DecodeDDoSProtection()
|
||||
if config != nil {
|
||||
return !config.IsPriorEmpty()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *Node) DecodeMaxCacheDiskCapacity() *shared.SizeCapacity {
|
||||
if this.MaxCacheDiskCapacity.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ignore error
|
||||
capacity, _ := shared.DecodeSizeCapacityJSON(this.MaxCacheDiskCapacity)
|
||||
return capacity
|
||||
}
|
||||
|
||||
func (this *Node) DecodeMaxCacheMemoryCapacity() *shared.SizeCapacity {
|
||||
if this.MaxCacheMemoryCapacity.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ignore error
|
||||
capacity, _ := shared.DecodeSizeCapacityJSON(this.MaxCacheMemoryCapacity)
|
||||
return capacity
|
||||
}
|
||||
|
||||
// DecodeDNSResolver 解析DNS解析主机配置
|
||||
func (this *Node) DecodeDNSResolver() *nodeconfigs.DNSResolverConfig {
|
||||
if this.DnsResolver.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var resolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||
err := json.Unmarshal(this.DnsResolver, resolverConfig)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
}
|
||||
return resolverConfig
|
||||
}
|
||||
|
||||
@@ -14,11 +14,12 @@ import (
|
||||
type NodeTaskType = string
|
||||
|
||||
const (
|
||||
NodeTaskTypeConfigChanged NodeTaskType = "configChanged"
|
||||
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged"
|
||||
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged"
|
||||
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged"
|
||||
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged"
|
||||
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
|
||||
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
|
||||
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged"
|
||||
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged"
|
||||
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged"
|
||||
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged"
|
||||
|
||||
// NS相关
|
||||
|
||||
|
||||
@@ -339,13 +339,19 @@ func (this *NSNodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstall
|
||||
}
|
||||
|
||||
// UpdateNodeStatus 更改节点状态
|
||||
func (this NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
|
||||
if statusJSON == nil {
|
||||
func (this NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
|
||||
if nodeStatus == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := this.Query(tx).
|
||||
|
||||
nodeStatusJSON, err := json.Marshal(nodeStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("status", string(statusJSON)).
|
||||
Set("status", nodeStatusJSON).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -264,13 +264,19 @@ func (this *ReportNodeDAO) FindEnabledNodeIdWithUniqueId(tx *dbs.Tx, uniqueId st
|
||||
}
|
||||
|
||||
// UpdateNodeStatus 更改节点状态
|
||||
func (this ReportNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
|
||||
if statusJSON == nil {
|
||||
func (this ReportNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *reporterconfigs.Status) error {
|
||||
if nodeStatus == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := this.Query(tx).
|
||||
|
||||
nodeStatusJSON, err := json.Marshal(nodeStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("status", string(statusJSON)).
|
||||
Set("status", nodeStatusJSON).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
|
||||
webId int64,
|
||||
reverseProxyJSON []byte,
|
||||
clusterId int64,
|
||||
includeNodesJSON string,
|
||||
excludeNodesJSON string,
|
||||
includeNodesJSON []byte,
|
||||
excludeNodesJSON []byte,
|
||||
groupIds []int64,
|
||||
userPlanId int64) (serverId int64, err error) {
|
||||
var op = NewServerOperator()
|
||||
@@ -206,15 +206,15 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
|
||||
op.Udp = udpJSON
|
||||
}
|
||||
op.WebId = webId
|
||||
if len(reverseProxyJSON) > 0 {
|
||||
if IsNotNull(reverseProxyJSON) {
|
||||
op.ReverseProxy = reverseProxyJSON
|
||||
}
|
||||
|
||||
op.ClusterId = clusterId
|
||||
if len(includeNodesJSON) > 0 {
|
||||
if IsNotNull(includeNodesJSON) {
|
||||
op.IncludeNodes = includeNodesJSON
|
||||
}
|
||||
if len(excludeNodesJSON) > 0 {
|
||||
if IsNotNull(excludeNodesJSON) {
|
||||
op.ExcludeNodes = excludeNodesJSON
|
||||
}
|
||||
|
||||
@@ -1476,6 +1476,7 @@ func (this *ServerDAO) FindAllServersDNSWithClusterId(tx *dbs.Tx, clusterId int6
|
||||
}
|
||||
|
||||
// FindAllEnabledServersWithDomain 根据域名查找服务
|
||||
// TODO 需要改成使用plainServerNames
|
||||
func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string) (result []*Server, err error) {
|
||||
if len(domain) == 0 {
|
||||
return
|
||||
@@ -1523,6 +1524,49 @@ func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string
|
||||
return
|
||||
}
|
||||
|
||||
// FindEnabledServerWithDomain 根据域名查找服务集群ID
|
||||
func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, domain string) (server *Server, err error) {
|
||||
if len(domain) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
one, err := this.Query(tx).
|
||||
State(ServerStateEnabled).
|
||||
Where("JSON_CONTAINS(plainServerNames, :domain)").
|
||||
Param("domain", strconv.Quote(domain)).
|
||||
Result("id", "userId", "clusterId").
|
||||
AscPk().
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if one != nil {
|
||||
return one.(*Server), nil
|
||||
}
|
||||
|
||||
// 尝试泛解析
|
||||
var dotIndex = strings.Index(domain, ".")
|
||||
if dotIndex > 0 {
|
||||
var wildcardDomain = "*." + domain[dotIndex+1:]
|
||||
one, err = this.Query(tx).
|
||||
State(ServerStateEnabled).
|
||||
Where("JSON_CONTAINS(plainServerNames, :domain)").
|
||||
Param("domain", strconv.Quote(wildcardDomain)).
|
||||
Result("id", "userId", "clusterId").
|
||||
AscPk().
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if one != nil {
|
||||
return one.(*Server), nil
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GenerateServerDNSName 重新生成子域名
|
||||
func (this *ServerDAO) GenerateServerDNSName(tx *dbs.Tx, serverId int64) (string, error) {
|
||||
if serverId <= 0 {
|
||||
@@ -1650,6 +1694,7 @@ func (this *ServerDAO) CheckUserServer(tx *dbs.Tx, userId int64, serverId int64)
|
||||
func (this *ServerDAO) UpdateUserServersClusterId(tx *dbs.Tx, userId int64, oldClusterId, newClusterId int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Attr("userId", userId).
|
||||
Attr("userPlanId", 0).
|
||||
Set("clusterId", newClusterId).
|
||||
Update()
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package models_test
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
@@ -10,10 +11,36 @@ import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestServerDAO_CreateManyServers(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var dao = models.NewServerDAO()
|
||||
var tx *dbs.Tx
|
||||
var count = 10000
|
||||
for i := 0; i < count; i++ {
|
||||
var serverNames = []*serverconfigs.ServerNameConfig{
|
||||
{
|
||||
Name: "s" + types.String(i) + ".teaos.cn",
|
||||
},
|
||||
}
|
||||
serverNamesJSON, err := json.Marshal(serverNames)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serverId, err := dao.CreateServer(tx, 0, 0, serverconfigs.ServerTypeHTTPProxy, "TEST"+types.String(i), "", serverNamesJSON, false, nil, nil, nil, nil, nil, nil, nil, 0, nil, 1, nil, nil, nil, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = serverId
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerDAO_ComposeServerConfig(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
var tx *dbs.Tx
|
||||
@@ -195,6 +222,25 @@ func TestServerDAO_FindAllEnabledServersWithDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerDAO_FindEnabledServerWithDomain(t *testing.T) {
|
||||
var dao = models.NewServerDAO()
|
||||
var tx *dbs.Tx
|
||||
|
||||
for _, domain := range []string{"a", "a.com", "teaos.cn", "www.teaos.cn", "cdn.teaos.cn", "google.com"} {
|
||||
var before = time.Now()
|
||||
server, err := dao.FindEnabledServerWithDomain(tx, domain)
|
||||
var costMs = time.Since(before).Seconds() * 1000
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if server == nil {
|
||||
t.Log(domain, "NULL", fmt.Sprintf("%.2fms", costMs))
|
||||
} else {
|
||||
t.Log(domain, string(maps.Map{"id": server.Id, "clusterId": server.ClusterId, "userId": server.UserId}.AsJSON()), fmt.Sprintf("%.2fms", costMs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ func (this *UserDAO) UpdateUser(tx *dbs.Tx, userId int64, username string, passw
|
||||
if userId <= 0 {
|
||||
return errors.New("invalid userId")
|
||||
}
|
||||
op := NewUserOperator()
|
||||
var op = NewUserOperator()
|
||||
op.Id = userId
|
||||
op.Username = username
|
||||
if len(password) > 0 {
|
||||
|
||||
@@ -254,13 +254,19 @@ func (this *UserNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
|
||||
}
|
||||
|
||||
// UpdateNodeStatus 更改节点状态
|
||||
func (this *UserNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
|
||||
if len(statusJSON) == 0 {
|
||||
func (this *UserNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
|
||||
if nodeStatus == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := this.Query(tx).
|
||||
|
||||
nodeStatusJSON, err := json.Marshal(nodeStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("status", string(statusJSON)).
|
||||
Set("status", nodeStatusJSON).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,18 +17,26 @@ type AliDNSProvider struct {
|
||||
|
||||
accessKeyId string
|
||||
accessKeySecret string
|
||||
regionId string
|
||||
}
|
||||
|
||||
// Auth 认证
|
||||
func (this *AliDNSProvider) Auth(params maps.Map) error {
|
||||
this.accessKeyId = params.GetString("accessKeyId")
|
||||
this.accessKeySecret = params.GetString("accessKeySecret")
|
||||
this.regionId = params.GetString("regionId")
|
||||
|
||||
if len(this.accessKeyId) == 0 {
|
||||
return errors.New("'accessKeyId' should not be empty")
|
||||
}
|
||||
if len(this.accessKeySecret) == 0 {
|
||||
return errors.New("'accessKeySecret' should not be empty")
|
||||
}
|
||||
|
||||
if len(this.regionId) == 0 {
|
||||
this.regionId = "cn-hangzhou"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -196,7 +204,7 @@ func (this *AliDNSProvider) DefaultRoute() string {
|
||||
func (this *AliDNSProvider) doAPI(req requests.AcsRequest, resp responses.AcsResponse) error {
|
||||
req.SetScheme("https")
|
||||
|
||||
client, err := alidns.NewClientWithAccessKey("cn-hangzhou", this.accessKeyId, this.accessKeySecret)
|
||||
client, err := alidns.NewClientWithAccessKey(this.regionId, this.accessKeyId, this.accessKeySecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func TestAliDNSProvider_AddRecord(t *testing.T) {
|
||||
Name: "test",
|
||||
Type: dnstypes.RecordTypeA,
|
||||
Value: "192.168.1.100",
|
||||
Route: "unicom",
|
||||
Route: "aliyun_r_cn-beijing",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -103,7 +103,7 @@ func testAliDNSProvider() (ProviderInterface, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
one, err := db.FindOne("SELECT * FROM edgeDNSProviders WHERE type='alidns' ORDER BY id DESC")
|
||||
one, err := db.FindOne("SELECT * FROM edgeDNSProviders WHERE type='alidns' AND state=1 ORDER BY id DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package nodes
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/accesslogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/configs"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/setup"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
@@ -35,6 +36,7 @@ import (
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -51,12 +53,18 @@ type APINode struct {
|
||||
sock *gosock.Sock
|
||||
|
||||
isStarting bool
|
||||
|
||||
issues []*StartIssue
|
||||
issuesFile string
|
||||
}
|
||||
|
||||
func NewAPINode() *APINode {
|
||||
return &APINode{
|
||||
serviceInstanceMap: map[string]interface{}{},
|
||||
sock: gosock.NewTmpSock(teaconst.ProcessName),
|
||||
|
||||
issues: []*StartIssue{},
|
||||
issuesFile: Tea.LogFile("issues.log"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,18 +73,27 @@ func (this *APINode) Start() {
|
||||
|
||||
logs.Println("[API_NODE]start api node, pid: " + strconv.Itoa(os.Getpid()))
|
||||
|
||||
// 检查数据库连接
|
||||
err := this.checkDB()
|
||||
if err != nil {
|
||||
logs.Println("[API_NODE]" + err.Error())
|
||||
return
|
||||
}
|
||||
// 保存启动过程中的问题,以便于查看
|
||||
defer func() {
|
||||
this.saveIssues()
|
||||
}()
|
||||
|
||||
// 本地Sock
|
||||
logs.Println("[API_NODE]listening sock ...")
|
||||
err = this.listenSock()
|
||||
err := this.listenSock()
|
||||
if err != nil {
|
||||
logs.Println("[API_NODE]" + err.Error())
|
||||
var errString = "start local sock failed: " + err.Error()
|
||||
logs.Println("[API_NODE]" + errString)
|
||||
this.addStartIssue("sock", errString, "")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查数据库连接
|
||||
err = this.checkDB()
|
||||
if err != nil {
|
||||
var errString = "check database connection failed: " + err.Error()
|
||||
logs.Println("[API_NODE]" + errString)
|
||||
this.addStartIssue("db", errString, this.dbIssueSuggestion(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -84,7 +101,9 @@ func (this *APINode) Start() {
|
||||
logs.Println("[API_NODE]auto upgrading ...")
|
||||
err = this.autoUpgrade()
|
||||
if err != nil {
|
||||
logs.Println("[API_NODE]auto upgrade failed: " + err.Error())
|
||||
var errString = "auto upgrade failed: " + err.Error()
|
||||
logs.Println("[API_NODE]" + errString)
|
||||
this.addStartIssue("db", errString, this.dbIssueSuggestion(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,7 +124,9 @@ func (this *APINode) Start() {
|
||||
logs.Println("[API_NODE]reading api config ...")
|
||||
config, err := configs.SharedAPIConfig()
|
||||
if err != nil {
|
||||
logs.Println("[API_NODE]start failed: " + err.Error())
|
||||
var errString = "read api config failed: " + err.Error()
|
||||
logs.Println("[API_NODE]" + errString)
|
||||
this.addStartIssue("config", errString, "")
|
||||
return
|
||||
}
|
||||
sharedAPIConfig = config
|
||||
@@ -113,15 +134,23 @@ func (this *APINode) Start() {
|
||||
// 校验
|
||||
apiNode, err := models.SharedAPINodeDAO.FindEnabledAPINodeWithUniqueIdAndSecret(nil, config.NodeId, config.Secret)
|
||||
if err != nil {
|
||||
logs.Println("[API_NODE]start failed: read api node from database failed: " + err.Error())
|
||||
var errString = "start failed: read api node from database failed: " + err.Error()
|
||||
logs.Println("[API_NODE]" + errString)
|
||||
this.addStartIssue("db", errString, "")
|
||||
return
|
||||
}
|
||||
if apiNode == nil {
|
||||
logs.Println("[API_NODE]can not start node, wrong 'nodeId' or 'secret'")
|
||||
var errString = "can not start node, wrong 'nodeId' or 'secret'"
|
||||
logs.Println("[API_NODE]" + errString)
|
||||
this.addStartIssue("config", errString, "请在api.yaml配置文件中填写正确的`nodeId`和`secret`,如果数据库或者管理节点或API节点是从别的服务器迁移过来的,请将老的系统配置拷贝到当前节点配置下")
|
||||
return
|
||||
}
|
||||
config.SetNumberId(int64(apiNode.Id))
|
||||
|
||||
// 清除上一次启动错误
|
||||
// 这个错误文件可能不存在,不需要处理错误
|
||||
_ = os.Remove(this.issuesFile)
|
||||
|
||||
// 设置rlimit
|
||||
_ = utils.SetRLimit(1024 * 1024)
|
||||
|
||||
@@ -138,10 +167,12 @@ func (this *APINode) Start() {
|
||||
// 监听RPC服务
|
||||
remotelogs.Println("API_NODE", "starting RPC server ...")
|
||||
|
||||
isListening := this.listenPorts(apiNode)
|
||||
var isListening = this.listenPorts(apiNode)
|
||||
|
||||
if !isListening {
|
||||
remotelogs.Error("API_NODE", "the api node require at least one listening address")
|
||||
var errString = "the api node require at least one listening address"
|
||||
remotelogs.Error("API_NODE", errString)
|
||||
this.addStartIssue("config", errString, "请给当前API节点设置一个监听端口")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -154,9 +185,8 @@ func (this *APINode) Start() {
|
||||
|
||||
// Daemon 实现守护进程
|
||||
func (this *APINode) Daemon() {
|
||||
path := os.TempDir() + "/edge-api.sock"
|
||||
isDebug := lists.ContainsString(os.Args, "debug")
|
||||
isDebug = true
|
||||
var path = os.TempDir() + "/" + teaconst.ProcessName + ".sock"
|
||||
var isDebug = lists.ContainsString(os.Args, "debug")
|
||||
for {
|
||||
conn, err := net.DialTimeout("unix", path, 1*time.Second)
|
||||
if err != nil {
|
||||
@@ -199,14 +229,14 @@ func (this *APINode) Daemon() {
|
||||
|
||||
// InstallSystemService 安装系统服务
|
||||
func (this *APINode) InstallSystemService() error {
|
||||
shortName := teaconst.SystemdServiceName
|
||||
var shortName = teaconst.SystemdServiceName
|
||||
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
manager := utils.NewServiceManager(shortName, teaconst.ProductName)
|
||||
var manager = utils.NewServiceManager(shortName, teaconst.ProductName)
|
||||
err = manager.Install(exe, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -242,21 +272,33 @@ func (this *APINode) checkDB() error {
|
||||
return err
|
||||
}
|
||||
|
||||
maxTries := 600
|
||||
for i := 0; i <= maxTries; i++ {
|
||||
_, err := db.Exec("SELECT 1")
|
||||
if err != nil {
|
||||
if i == maxTries-1 {
|
||||
return err
|
||||
} else {
|
||||
if i%10 == 0 { // 这让提示不会太多
|
||||
logs.Println("[API_NODE]reconnecting to database (" + fmt.Sprintf("%.1f", float32(i*100)/float32(maxTries+1)) + "%) ...")
|
||||
// 第一次测试连接
|
||||
_, err = db.Exec("SELECT 1")
|
||||
if err != nil {
|
||||
var errString = "check database connection failed: " + err.Error()
|
||||
logs.Println("[API_NODE]" + errString)
|
||||
this.addStartIssue("db", errString, this.dbIssueSuggestion(errString))
|
||||
|
||||
// 多次尝试
|
||||
var maxTries = 600
|
||||
if Tea.IsTesting() {
|
||||
maxTries = 600
|
||||
}
|
||||
for i := 0; i <= maxTries; i++ {
|
||||
_, err := db.Exec("SELECT 1")
|
||||
if err != nil {
|
||||
if i == maxTries-1 {
|
||||
return err
|
||||
} else {
|
||||
if i%10 == 0 { // 这让提示不会太多
|
||||
logs.Println("[API_NODE]check database connection failed: " + err.Error() + ", reconnecting to database ...")
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
} else {
|
||||
logs.Println("[API_NODE]database connected")
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
logs.Println("[API_NODE]database connected")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +312,7 @@ func (this *APINode) autoUpgrade() error {
|
||||
}
|
||||
|
||||
// 执行SQL
|
||||
config := &dbs.Config{}
|
||||
var config = &dbs.Config{}
|
||||
configData, err := ioutil.ReadFile(Tea.ConfigFile("db.yaml"))
|
||||
if err != nil {
|
||||
return errors.New("read database config file failed: " + err.Error())
|
||||
@@ -681,3 +723,62 @@ func (this *APINode) unaryInterceptor(ctx context.Context, req interface{}, info
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 添加启动相关的Issue
|
||||
func (this *APINode) addStartIssue(code string, message string, suggestion string) {
|
||||
this.issues = append(this.issues, NewStartIssue(code, message, suggestion))
|
||||
this.saveIssues()
|
||||
}
|
||||
|
||||
// 增加数据库建议
|
||||
func (this *APINode) dbIssueSuggestion(errString string) string {
|
||||
// 数据库配置
|
||||
db, err := dbs.Default()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
config, err := db.Config()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var dsn = config.Dsn
|
||||
dsnConfig, err := mysql.ParseDSN(dsn)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
var addr = dsnConfig.Addr
|
||||
|
||||
// 配置文件位置
|
||||
var dbConfigPath = Tea.ConfigFile("db.yaml")
|
||||
|
||||
// 连接被拒绝
|
||||
if strings.Contains(errString, "connection refused") {
|
||||
// 本机
|
||||
if strings.HasPrefix(addr, "127.0.0.1:") || strings.HasPrefix(addr, "localhost:") {
|
||||
return "试图连接到数据库被拒绝,请检查:1)本地数据库服务是否已经启动;2)数据库IP和端口(" + addr + ")是否正确;(当前数据库配置为:" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
|
||||
} else {
|
||||
return "试图连接到数据库被拒绝,请检查:1)数据库服务是否已经启动;2)数据库IP和端口(" + addr + ")是否正确;3)防火墙设置;(当前数据库配置为:" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
|
||||
}
|
||||
}
|
||||
|
||||
// 权限错误
|
||||
if strings.Contains(errString, "Error 1045") || strings.Contains(errString, "Error 1044") {
|
||||
return "使用的用户和密码没有权限连接到指定数据库,请检查:1)数据库配置文件中的用户名(" + dsnConfig.User + ")和密码(" + dsnConfig.Passwd + ")是否正确;2)使用的用户是否已经在数据库中设置了正确的权限;(当前数据库配置为:" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
|
||||
}
|
||||
|
||||
// 数据库名称错误
|
||||
if strings.Contains(errString, "Error 1049") {
|
||||
return "数据库名称配置错误,请检查:数据库配置文件中数据库名称(" + dsnConfig.DBName + ")是否正确;(当前数据库配置为:" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// 保存issues
|
||||
func (this *APINode) saveIssues() {
|
||||
issuesJSON, err := json.Marshal(this.issues)
|
||||
if err == nil {
|
||||
_ = ioutil.WriteFile(this.issuesFile, issuesJSON, 0666)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,6 +570,18 @@ func (this *APINode) registerServices(server *grpc.Server) {
|
||||
this.rest(instance)
|
||||
}
|
||||
|
||||
{
|
||||
instance := this.serviceInstance(&services.HTTPCacheTaskKeyService{}).(*services.HTTPCacheTaskKeyService)
|
||||
pb.RegisterHTTPCacheTaskKeyServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
|
||||
{
|
||||
instance := this.serviceInstance(&services.HTTPCacheTaskService{}).(*services.HTTPCacheTaskService)
|
||||
pb.RegisterHTTPCacheTaskServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
|
||||
APINodeServicesRegister(this, server)
|
||||
|
||||
// TODO check service names
|
||||
|
||||
17
internal/nodes/start_issue.go
Normal file
17
internal/nodes/start_issue.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package nodes
|
||||
|
||||
type StartIssue struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Suggestion string `json:"suggestion"`
|
||||
}
|
||||
|
||||
func NewStartIssue(code string, message string, suggestion string) *StartIssue {
|
||||
return &StartIssue{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Suggestion: suggestion,
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NSNodeService 域名服务器节点服务
|
||||
@@ -398,9 +399,18 @@ func (this *NSNodeService) UpdateNSNodeStatus(ctx context.Context, req *pb.Updat
|
||||
return nil, errors.New("'nodeId' should be greater than 0")
|
||||
}
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedNSNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON)
|
||||
// 修改时间戳
|
||||
var nodeStatus = &nodeconfigs.NodeStatus{}
|
||||
err = json.Unmarshal(req.StatusJSON, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode node status json failed: " + err.Error())
|
||||
}
|
||||
nodeStatus.UpdatedAt = time.Now().Unix()
|
||||
|
||||
// 保存
|
||||
err = models.SharedNSNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/authority"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AuthorityNodeService struct {
|
||||
@@ -223,9 +226,18 @@ func (this *AuthorityNodeService) UpdateAuthorityNodeStatus(ctx context.Context,
|
||||
return nil, errors.New("'nodeId' should be greater than 0")
|
||||
}
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = authority.SharedAuthorityNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON)
|
||||
// 修改时间戳
|
||||
var nodeStatus = &nodeconfigs.NodeStatus{}
|
||||
err = json.Unmarshal(req.StatusJSON, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode node status json failed: " + err.Error())
|
||||
}
|
||||
nodeStatus.UpdatedAt = time.Now().Unix()
|
||||
|
||||
// 保存
|
||||
err = authority.SharedAuthorityNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func (this *DNSProviderService) CountAllEnabledDNSProviders(ctx context.Context,
|
||||
|
||||
tx := this.NullTx()
|
||||
|
||||
count, err := dns.SharedDNSProviderDAO.CountAllEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain)
|
||||
count, err := dns.SharedDNSProviderDAO.CountAllEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain, req.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -76,9 +76,9 @@ func (this *DNSProviderService) ListEnabledDNSProviders(ctx context.Context, req
|
||||
|
||||
// TODO 校验权限
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
|
||||
providers, err := dns.SharedDNSProviderDAO.ListEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain, req.Offset, req.Size)
|
||||
providers, err := dns.SharedDNSProviderDAO.ListEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain, req.Type, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
383
internal/rpc/services/service_http_cache_task.go
Normal file
383
internal/rpc/services/service_http_cache_task.go
Normal file
@@ -0,0 +1,383 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
// HTTPCacheTaskService 缓存任务管理
|
||||
type HTTPCacheTaskService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// CreateHTTPCacheTask 创建任务
|
||||
func (this *HTTPCacheTaskService) CreateHTTPCacheTask(ctx context.Context, req *pb.CreateHTTPCacheTaskRequest) (*pb.CreateHTTPCacheTaskResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查操作类型
|
||||
if req.Type != models.HTTPCacheTaskTypePurge && req.Type != models.HTTPCacheTaskTypeFetch {
|
||||
return nil, errors.New("invalid type '" + req.Type + "'")
|
||||
}
|
||||
|
||||
// 检查Key数量
|
||||
var clusterId int64
|
||||
if userId > 0 {
|
||||
// 限制单次
|
||||
var maxKeysPerTask = userconfigs.MaxCacheKeysPerTask
|
||||
var maxKeysPerDay = userconfigs.MaxCacheKeysPerDay
|
||||
|
||||
serverConfig, err := models.SharedSysSettingDAO.ReadUserServerConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if serverConfig != nil {
|
||||
switch req.Type {
|
||||
case models.HTTPCacheTaskTypePurge:
|
||||
if serverConfig.HTTPCacheTaskPurgeConfig != nil {
|
||||
if serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerTask > 0 {
|
||||
maxKeysPerTask = serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerTask
|
||||
}
|
||||
if serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerDay > 0 {
|
||||
maxKeysPerDay = serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerDay
|
||||
}
|
||||
}
|
||||
case models.HTTPCacheTaskTypeFetch:
|
||||
if serverConfig.HTTPCacheTaskFetchConfig != nil {
|
||||
if serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerTask > 0 {
|
||||
maxKeysPerTask = serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerTask
|
||||
}
|
||||
if serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerDay > 0 {
|
||||
maxKeysPerDay = serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerDay
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if maxKeysPerTask > 0 && len(req.Keys) > types.Int(maxKeysPerTask) {
|
||||
return nil, errors.New("too many keys in task (current:" + types.String(len(req.Keys)) + ", max:" + types.String(maxKeysPerTask) + ")")
|
||||
}
|
||||
|
||||
if maxKeysPerDay > 0 {
|
||||
countInDay, err := models.SharedHTTPCacheTaskKeyDAO.CountUserTasksInDay(tx, userId, timeutil.Format("Ymd"), req.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if types.Int(countInDay)+len(req.Keys) > types.Int(maxKeysPerDay) {
|
||||
return nil, errors.New("too many keys in today (current:" + types.String(types.Int(countInDay)+len(req.Keys)) + ", max:" + types.String(maxKeysPerDay) + ")")
|
||||
}
|
||||
}
|
||||
|
||||
clusterId, err = models.SharedUserDAO.FindUserClusterId(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 创建任务
|
||||
taskId, err := models.SharedHTTPCacheTaskDAO.CreateTask(tx, userId, req.Type, req.KeyType, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var countKeys = 0
|
||||
var domainMap = map[string]*models.Server{} // domain name => *Server
|
||||
for _, key := range req.Keys {
|
||||
if len(key) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取域名
|
||||
var domain = utils.ParseDomainFromKey(key)
|
||||
if len(domain) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 查询所在集群
|
||||
server, ok := domainMap[domain]
|
||||
if !ok {
|
||||
server, err = models.SharedServerDAO.FindEnabledServerWithDomain(tx, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if server == nil {
|
||||
continue
|
||||
}
|
||||
domainMap[domain] = server
|
||||
}
|
||||
|
||||
// 检查用户
|
||||
if userId > 0 {
|
||||
if int64(server.UserId) != userId {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var serverClusterId = int64(server.ClusterId)
|
||||
if serverClusterId == 0 {
|
||||
if clusterId > 0 {
|
||||
serverClusterId = clusterId
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
_, err = models.SharedHTTPCacheTaskKeyDAO.CreateKey(tx, taskId, key, req.Type, req.KeyType, serverClusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
countKeys++
|
||||
}
|
||||
|
||||
if countKeys == 0 {
|
||||
// 如果没有有效的Key,则直接完成
|
||||
err = models.SharedHTTPCacheTaskDAO.UpdateTaskStatus(tx, taskId, true, true)
|
||||
} else {
|
||||
err = models.SharedHTTPCacheTaskDAO.UpdateTaskReady(tx, taskId)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.CreateHTTPCacheTaskResponse{
|
||||
HttpCacheTaskId: taskId,
|
||||
CountKeys: int64(countKeys),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CountHTTPCacheTasks 计算任务数量
|
||||
func (this *HTTPCacheTaskService) CountHTTPCacheTasks(ctx context.Context, req *pb.CountHTTPCacheTasksRequest) (*pb.RPCCountResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
count, err := models.SharedHTTPCacheTaskDAO.CountTasks(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// CountDoingHTTPCacheTasks 计算正在执行的任务数量
|
||||
func (this *HTTPCacheTaskService) CountDoingHTTPCacheTasks(ctx context.Context, req *pb.CountDoingHTTPCacheTasksRequest) (*pb.RPCCountResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
count, err := models.SharedHTTPCacheTaskDAO.CountDoingTasks(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// ListHTTPCacheTasks 列出单页任务
|
||||
func (this *HTTPCacheTaskService) ListHTTPCacheTasks(ctx context.Context, req *pb.ListHTTPCacheTasksRequest) (*pb.ListHTTPCacheTasksResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
tasks, err := models.SharedHTTPCacheTaskDAO.ListTasks(tx, userId, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbTasks = []*pb.HTTPCacheTask{}
|
||||
var cacheMap = utils.NewCacheMap()
|
||||
for _, task := range tasks {
|
||||
var taskId = int64(task.Id)
|
||||
|
||||
// 查询所属用户
|
||||
var pbUser = &pb.User{}
|
||||
if task.UserId > 0 {
|
||||
var taskUserId = int64(task.UserId)
|
||||
if taskUserId > 0 {
|
||||
taskUser, err := models.SharedUserDAO.FindEnabledUser(tx, taskUserId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if taskUser == nil {
|
||||
// 找不到用户就删除
|
||||
err = models.SharedHTTPCacheTaskDAO.DisableHTTPCacheTask(tx, taskUserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
pbUser = &pb.User{
|
||||
Id: int64(taskUser.Id),
|
||||
Username: taskUser.Username,
|
||||
Fullname: taskUser.Fullname,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pbTasks = append(pbTasks, &pb.HTTPCacheTask{
|
||||
Id: taskId,
|
||||
UserId: int64(task.UserId),
|
||||
Type: task.Type,
|
||||
KeyType: task.KeyType,
|
||||
CreatedAt: int64(task.CreatedAt),
|
||||
DoneAt: int64(task.DoneAt),
|
||||
IsDone: task.IsDone,
|
||||
IsOk: task.IsOk,
|
||||
Description: task.Description,
|
||||
User: pbUser,
|
||||
HttpCacheTaskKeys: nil,
|
||||
})
|
||||
}
|
||||
return &pb.ListHTTPCacheTasksResponse{
|
||||
HttpCacheTasks: pbTasks,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FindEnabledHTTPCacheTask 查找单个任务
|
||||
func (this *HTTPCacheTaskService) FindEnabledHTTPCacheTask(ctx context.Context, req *pb.FindEnabledHTTPCacheTaskRequest) (*pb.FindEnabledHTTPCacheTaskResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
if userId > 0 {
|
||||
err = models.SharedHTTPCacheTaskDAO.CheckUserTask(tx, userId, req.HttpCacheTaskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
task, err := models.SharedHTTPCacheTaskDAO.FindEnabledHTTPCacheTask(tx, req.HttpCacheTaskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if task == nil {
|
||||
return &pb.FindEnabledHTTPCacheTaskResponse{HttpCacheTask: nil}, nil
|
||||
}
|
||||
|
||||
// 查询所属用户
|
||||
var pbUser = &pb.User{}
|
||||
if task.UserId > 0 {
|
||||
var taskUserId = int64(task.UserId)
|
||||
if taskUserId > 0 {
|
||||
taskUser, err := models.SharedUserDAO.FindEnabledUser(tx, taskUserId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if taskUser == nil {
|
||||
// 找不到用户就删除
|
||||
err = models.SharedHTTPCacheTaskDAO.DisableHTTPCacheTask(tx, taskUserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
pbUser = &pb.User{
|
||||
Id: int64(taskUser.Id),
|
||||
Username: taskUser.Username,
|
||||
Fullname: taskUser.Fullname,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keys
|
||||
keys, err := models.SharedHTTPCacheTaskKeyDAO.FindAllTaskKeys(tx, req.HttpCacheTaskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pbKeys = []*pb.HTTPCacheTaskKey{}
|
||||
for _, key := range keys {
|
||||
|
||||
pbKeys = append(pbKeys, &pb.HTTPCacheTaskKey{
|
||||
Id: int64(key.Id),
|
||||
TaskId: int64(key.TaskId),
|
||||
Key: key.Key,
|
||||
KeyType: key.KeyType,
|
||||
IsDone: key.IsDone,
|
||||
IsDoing: !key.IsDone && len(key.DecodeNodes()) > 0,
|
||||
ErrorsJSON: key.Errors,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.FindEnabledHTTPCacheTaskResponse{
|
||||
HttpCacheTask: &pb.HTTPCacheTask{
|
||||
Id: int64(task.Id),
|
||||
UserId: int64(task.UserId),
|
||||
Type: task.Type,
|
||||
KeyType: task.KeyType,
|
||||
CreatedAt: int64(task.CreatedAt),
|
||||
DoneAt: int64(task.DoneAt),
|
||||
IsDone: task.IsDone,
|
||||
IsOk: task.IsOk,
|
||||
User: pbUser,
|
||||
HttpCacheTaskKeys: pbKeys,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteHTTPCacheTask 删除任务
|
||||
func (this *HTTPCacheTaskService) DeleteHTTPCacheTask(ctx context.Context, req *pb.DeleteHTTPCacheTaskRequest) (*pb.RPCSuccess, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
if userId > 0 {
|
||||
err = models.SharedHTTPCacheTaskDAO.CheckUserTask(tx, userId, req.HttpCacheTaskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedHTTPCacheTaskDAO.DisableHTTPCacheTask(tx, req.HttpCacheTaskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// ResetHTTPCacheTask 重置任务状态
|
||||
// 只允许管理员重置,用于调试
|
||||
func (this *HTTPCacheTaskService) ResetHTTPCacheTask(ctx context.Context, req *pb.ResetHTTPCacheTaskRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 重置任务
|
||||
err = models.SharedHTTPCacheTaskDAO.ResetTask(tx, req.HttpCacheTaskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 重置任务下的Key
|
||||
err = models.SharedHTTPCacheTaskKeyDAO.ResetCacheKeysWithTaskId(tx, req.HttpCacheTaskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
173
internal/rpc/services/service_http_cache_task_key.go
Normal file
173
internal/rpc/services/service_http_cache_task_key.go
Normal file
@@ -0,0 +1,173 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
// HTTPCacheTaskKeyService 缓存任务Key管理
|
||||
type HTTPCacheTaskKeyService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// ValidateHTTPCacheTaskKeys 校验缓存Key
|
||||
func (this *HTTPCacheTaskKeyService) ValidateHTTPCacheTaskKeys(ctx context.Context, req *pb.ValidateHTTPCacheTaskKeysRequest) (*pb.ValidateHTTPCacheTaskKeysResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
|
||||
// 检查Key数量
|
||||
var clusterId int64
|
||||
if userId > 0 {
|
||||
clusterId, err = models.SharedUserDAO.FindUserClusterId(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pbFailResults = []*pb.ValidateHTTPCacheTaskKeysResponse_FailKey{}
|
||||
var domainMap = map[string]*models.Server{} // domain name => *Server
|
||||
for _, key := range req.Keys {
|
||||
if len(key) == 0 {
|
||||
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
|
||||
Key: key,
|
||||
ReasonCode: "requireKey",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取域名
|
||||
var domain = utils.ParseDomainFromKey(key)
|
||||
if len(domain) == 0 {
|
||||
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
|
||||
Key: key,
|
||||
ReasonCode: "requireDomain",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// 查询所在集群
|
||||
server, ok := domainMap[domain]
|
||||
if !ok {
|
||||
server, err = models.SharedServerDAO.FindEnabledServerWithDomain(tx, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if server == nil {
|
||||
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
|
||||
Key: key,
|
||||
ReasonCode: "requireServer",
|
||||
})
|
||||
continue
|
||||
}
|
||||
domainMap[domain] = server
|
||||
}
|
||||
|
||||
// 检查用户
|
||||
if userId > 0 {
|
||||
if int64(server.UserId) != userId {
|
||||
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
|
||||
Key: key,
|
||||
ReasonCode: "requireUser",
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var serverClusterId = int64(server.ClusterId)
|
||||
if serverClusterId == 0 {
|
||||
if clusterId > 0 {
|
||||
serverClusterId = clusterId
|
||||
} else {
|
||||
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
|
||||
Key: key,
|
||||
ReasonCode: "requireClusterId",
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.ValidateHTTPCacheTaskKeysResponse{FailKeys: pbFailResults}, nil
|
||||
}
|
||||
|
||||
// FindDoingHTTPCacheTaskKeys 查找需要执行的Key
|
||||
func (this *HTTPCacheTaskKeyService) FindDoingHTTPCacheTaskKeys(ctx context.Context, req *pb.FindDoingHTTPCacheTaskKeysRequest) (*pb.FindDoingHTTPCacheTaskKeysResponse, error) {
|
||||
nodeId, err := this.ValidateNode(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.Size <= 0 {
|
||||
req.Size = 100
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
keys, err := models.SharedHTTPCacheTaskKeyDAO.FindDoingTaskKeys(tx, nodeId, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbKeys = []*pb.HTTPCacheTaskKey{}
|
||||
for _, key := range keys {
|
||||
pbKeys = append(pbKeys, &pb.HTTPCacheTaskKey{
|
||||
Id: int64(key.Id),
|
||||
TaskId: int64(key.TaskId),
|
||||
Key: key.Key,
|
||||
Type: key.Type,
|
||||
KeyType: key.KeyType,
|
||||
NodeClusterId: int64(key.ClusterId),
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.FindDoingHTTPCacheTaskKeysResponse{HttpCacheTaskKeys: pbKeys}, nil
|
||||
}
|
||||
|
||||
// UpdateHTTPCacheTaskKeysStatus 更新一组Key状态
|
||||
func (this *HTTPCacheTaskKeyService) UpdateHTTPCacheTaskKeysStatus(ctx context.Context, req *pb.UpdateHTTPCacheTaskKeysStatusRequest) (*pb.RPCSuccess, error) {
|
||||
nodeId, err := this.ValidateNode(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
|
||||
var nodesJSONMap = map[int64][]byte{} // clusterId => nodesJSON
|
||||
|
||||
for _, result := range req.KeyResults {
|
||||
// 集群Id
|
||||
var clusterId = result.NodeClusterId
|
||||
nodesJSON, ok := nodesJSONMap[clusterId]
|
||||
if !ok {
|
||||
nodeIdsInCluster, err := models.SharedNodeDAO.FindEnabledAndOnNodeIdsWithClusterId(tx, clusterId, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var nodeMap = map[int64]bool{}
|
||||
for _, nodeIdInCluster := range nodeIdsInCluster {
|
||||
nodeMap[nodeIdInCluster] = true
|
||||
}
|
||||
nodesJSON, err = json.Marshal(nodeMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodesJSONMap[clusterId] = nodesJSON
|
||||
}
|
||||
|
||||
err = models.SharedHTTPCacheTaskKeyDAO.UpdateKeyStatus(tx, result.Id, nodeId, result.Error, nodesJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
23
internal/rpc/services/service_http_cache_task_test.go
Normal file
23
internal/rpc/services/service_http_cache_task_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHTTPCacheTaskService_CountHTTPCacheTasks(t *testing.T) {
|
||||
var a = assert.NewAssertion(t)
|
||||
|
||||
var service = &HTTPCacheTaskService{}
|
||||
a.IsTrue(service.parseDomain("aaa") == "aaa")
|
||||
a.IsTrue(service.parseDomain("AAA") == "aaa")
|
||||
a.IsTrue(service.parseDomain("a.b-c.com") == "a.b-c.com")
|
||||
a.IsTrue(service.parseDomain("a.b-c.com/hello/world") == "a.b-c.com")
|
||||
a.IsTrue(service.parseDomain("https://a.b-c.com") == "a.b-c.com")
|
||||
a.IsTrue(service.parseDomain("http://a.b-c.com/hello/world") == "a.b-c.com")
|
||||
a.IsTrue(service.parseDomain("http://a.B-c.com/hello/world") == "a.b-c.com")
|
||||
a.IsTrue(service.parseDomain("http:/aaaa.com") == "http")
|
||||
a.IsTrue(service.parseDomain("北京") == "")
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
|
||||
return nil, err
|
||||
}
|
||||
|
||||
templatePolicy := firewallconfigs.HTTPFirewallTemplate()
|
||||
var templatePolicy = firewallconfigs.HTTPFirewallTemplate()
|
||||
|
||||
tx := this.NullTx()
|
||||
|
||||
@@ -186,18 +186,18 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
|
||||
return nil, errors.New("can not found firewall policy")
|
||||
}
|
||||
|
||||
inboundConfig := firewallPolicy.Inbound
|
||||
var inboundConfig = firewallPolicy.Inbound
|
||||
if inboundConfig == nil {
|
||||
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||
}
|
||||
|
||||
outboundConfig := firewallPolicy.Outbound
|
||||
var outboundConfig = firewallPolicy.Outbound
|
||||
if outboundConfig == nil {
|
||||
outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
|
||||
}
|
||||
|
||||
// 更新老的
|
||||
oldCodes := []string{}
|
||||
var oldCodes = []string{}
|
||||
if firewallPolicy.Inbound != nil {
|
||||
for _, g := range firewallPolicy.Inbound.Groups {
|
||||
if len(g.Code) > 0 {
|
||||
@@ -301,7 +301,7 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedHTTPFirewallPolicyDAO.UpdateFirewallPolicy(tx, req.HttpFirewallPolicyId, req.IsOn, req.Name, req.Description, inboundConfigJSON, outboundConfigJSON, req.BlockOptionsJSON, req.Mode, req.UseLocalFirewall, synFloodConfig, logConfig)
|
||||
err = models.SharedHTTPFirewallPolicyDAO.UpdateFirewallPolicy(tx, req.HttpFirewallPolicyId, req.IsOn, req.Name, req.Description, inboundConfigJSON, outboundConfigJSON, req.BlockOptionsJSON, req.CaptchaOptionsJSON, req.Mode, req.UseLocalFirewall, synFloodConfig, logConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
20
internal/rpc/services/service_http_web_community.go
Normal file
20
internal/rpc/services/service_http_web_community.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// UpdateHTTPWebUAM 修改UAM设置
|
||||
func (this *HTTPWebService) UpdateHTTPWebUAM(ctx context.Context, req *pb.UpdateHTTPWebUAMRequest) (*pb.RPCSuccess, error) {
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindHTTPWebUAM 查找UAM设置
|
||||
func (this *HTTPWebService) FindHTTPWebUAM(ctx context.Context, req *pb.FindHTTPWebUAMRequest) (*pb.FindHTTPWebUAMResponse, error) {
|
||||
return &pb.FindHTTPWebUAMResponse{UamJSON: nil}, nil
|
||||
}
|
||||
@@ -114,23 +114,42 @@ func (this *IPItemService) DeleteIPItem(ctx context.Context, req *pb.DeleteIPIte
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
|
||||
if userId > 0 {
|
||||
listId, err := models.SharedIPItemDAO.FindItemListId(tx, req.IpItemId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// 如果是使用IPItemId删除
|
||||
if req.IpItemId > 0 {
|
||||
if userId > 0 {
|
||||
listId, err := models.SharedIPItemDAO.FindItemListId(tx, req.IpItemId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, listId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, listId)
|
||||
err = models.SharedIPItemDAO.DisableIPItem(tx, req.IpItemId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedIPItemDAO.DisableIPItem(tx, req.IpItemId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// 如果是使用ipFrom+ipTo删除
|
||||
if len(req.IpFrom) > 0 {
|
||||
// 检查IP列表
|
||||
if req.IpListId > 0 && userId > 0 {
|
||||
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, req.IpListId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedIPItemDAO.DisableIPItemsWithIP(tx, req.IpFrom, req.IpTo, userId, req.IpListId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
|
||||
@@ -21,9 +21,20 @@ func (this *IPListService) CreateIPList(ctx context.Context, req *pb.CreateIPLis
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
|
||||
listId, err := models.SharedIPListDAO.CreateIPList(tx, userId, req.Type, req.Name, req.Code, req.TimeoutJSON, req.Description, req.IsPublic, req.IsGlobal)
|
||||
// 检查用户相关信息
|
||||
if userId > 0 {
|
||||
// 检查服务ID
|
||||
if req.ServerId > 0 {
|
||||
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listId, err := models.SharedIPListDAO.CreateIPList(tx, userId, req.ServerId, req.Type, req.Name, req.Code, req.TimeoutJSON, req.Description, req.IsPublic, req.IsGlobal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,12 +61,18 @@ func (this *IPListService) UpdateIPList(ctx context.Context, req *pb.UpdateIPLis
|
||||
// FindEnabledIPList 查找IP列表
|
||||
func (this *IPListService) FindEnabledIPList(ctx context.Context, req *pb.FindEnabledIPListRequest) (*pb.FindEnabledIPListResponse, error) {
|
||||
// 校验请求
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
if userId > 0 {
|
||||
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, req.IpListId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
list, err := models.SharedIPListDAO.FindEnabledIPList(tx, req.IpListId, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -10,17 +10,18 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/installers"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/andybalholm/brotli"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"io"
|
||||
@@ -399,7 +400,7 @@ func (this *NodeService) FindAllEnabledNodesWithNodeClusterId(ctx context.Contex
|
||||
|
||||
tx := this.NullTx()
|
||||
|
||||
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(tx, req.NodeClusterId)
|
||||
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(tx, req.NodeClusterId, req.IncludeSecondary)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -767,13 +768,14 @@ func (this *NodeService) FindCurrentNodeConfig(ctx context.Context, req *pb.Find
|
||||
NodeJSON: data,
|
||||
DataSize: int64(len(data)),
|
||||
IsCompressed: isCompressed,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateNodeStatus 更新节点状态
|
||||
func (this *NodeService) UpdateNodeStatus(ctx context.Context, req *pb.UpdateNodeStatusRequest) (*pb.RPCSuccess, error) {
|
||||
// 校验节点
|
||||
_, _, nodeId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeNode)
|
||||
nodeId, err := this.ValidateNode(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -786,9 +788,18 @@ func (this *NodeService) UpdateNodeStatus(ctx context.Context, req *pb.UpdateNod
|
||||
return nil, errors.New("'nodeId' should be greater than 0")
|
||||
}
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON)
|
||||
// 修改时间戳
|
||||
var nodeStatus = &nodeconfigs.NodeStatus{}
|
||||
err = json.Unmarshal(req.StatusJSON, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode node status json failed: " + err.Error())
|
||||
}
|
||||
nodeStatus.UpdatedAt = time.Now().Unix()
|
||||
|
||||
// 保存
|
||||
err = models.SharedNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -823,7 +834,7 @@ func (this *NodeService) InstallNode(ctx context.Context, req *pb.InstallNodeReq
|
||||
goman.New(func() {
|
||||
err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, false)
|
||||
if err != nil {
|
||||
logs.Println("[RPC]install node:" + err.Error())
|
||||
remotelogs.Error("NODE_SERVICE", "install node failed:"+err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -863,7 +874,7 @@ func (this *NodeService) UpgradeNode(ctx context.Context, req *pb.UpgradeNodeReq
|
||||
goman.New(func() {
|
||||
err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, true)
|
||||
if err != nil {
|
||||
logs.Println("[RPC]install node:" + err.Error())
|
||||
remotelogs.Error("NODE_SERVICE", "install node:"+err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1746,3 +1757,204 @@ func (this *NodeService) FindNodeLevelInfo(ctx context.Context, req *pb.FindNode
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindNodeDNSResolver 读取节点DNS Resolver
|
||||
func (this *NodeService) FindNodeDNSResolver(ctx context.Context, req *pb.FindNodeDNSResolverRequest) (*pb.FindNodeDNSResolverResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
config, err := models.SharedNodeDAO.FindNodeDNSResolver(tx, req.NodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.FindNodeDNSResolverResponse{
|
||||
DnsResolverJSON: configJSON,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateNodeDNSResolver 修改DNS Resolver
|
||||
func (this *NodeService) UpdateNodeDNSResolver(ctx context.Context, req *pb.UpdateNodeDNSResolverRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
var config = nodeconfigs.DefaultDNSResolverConfig()
|
||||
err = json.Unmarshal(req.DnsResolverJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = models.SharedNodeDAO.UpdateNodeDNSResolver(tx, req.NodeId, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindNodeDDoSProtection 获取集群的DDoS设置
|
||||
func (this *NodeService) FindNodeDDoSProtection(ctx context.Context, req *pb.FindNodeDDoSProtectionRequest) (*pb.FindNodeDDoSProtectionResponse, error) {
|
||||
var nodeId = req.NodeId
|
||||
var isFromNode = false
|
||||
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
// 检查是否来自节点
|
||||
currentNodeId, err2 := this.ValidateNode(ctx)
|
||||
if err2 != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if nodeId > 0 && currentNodeId != nodeId {
|
||||
return nil, errors.New("invalid 'nodeId'")
|
||||
}
|
||||
|
||||
nodeId = currentNodeId
|
||||
isFromNode = true
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
ddosProtection, err := models.SharedNodeDAO.FindNodeDDoSProtection(tx, nodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ddosProtection == nil {
|
||||
ddosProtection = ddosconfigs.DefaultProtectionConfig()
|
||||
}
|
||||
|
||||
// 组合父级节点配置
|
||||
// 只有从节点读取配置时才需要组合
|
||||
if isFromNode {
|
||||
clusterId, err := models.SharedNodeDAO.FindNodeClusterId(tx, nodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if clusterId > 0 {
|
||||
clusterDDoSProtection, err := models.SharedNodeClusterDAO.FindClusterDDoSProtection(tx, clusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if clusterDDoSProtection == nil {
|
||||
clusterDDoSProtection = ddosconfigs.DefaultProtectionConfig()
|
||||
}
|
||||
|
||||
clusterDDoSProtection.Merge(ddosProtection)
|
||||
ddosProtection = clusterDDoSProtection
|
||||
}
|
||||
}
|
||||
|
||||
ddosProtectionJSON, err := json.Marshal(ddosProtection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result = &pb.FindNodeDDoSProtectionResponse{
|
||||
DdosProtectionJSON: ddosProtectionJSON,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateNodeDDoSProtection 修改集群的DDOS设置
|
||||
func (this *NodeService) UpdateNodeDDoSProtection(ctx context.Context, req *pb.UpdateNodeDDoSProtectionRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ddosProtection = &ddosconfigs.ProtectionConfig{}
|
||||
err = json.Unmarshal(req.DdosProtectionJSON, ddosProtection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
err = models.SharedNodeDAO.UpdateNodeDDoSProtection(tx, req.NodeId, ddosProtection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindEnabledNodeConfigInfo 取得节点的配置概要信息
|
||||
func (this *NodeService) FindEnabledNodeConfigInfo(ctx context.Context, req *pb.FindEnabledNodeConfigInfoRequest) (*pb.FindEnabledNodeConfigInfoResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
var result = &pb.FindEnabledNodeConfigInfoResponse{}
|
||||
node, err := models.SharedNodeDAO.FindEnabledNode(tx, req.NodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node == nil {
|
||||
// 总是返回非空
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// dns
|
||||
if len(node.DNSRouteCodes()) > 0 {
|
||||
result.HasDNSInfo = true
|
||||
}
|
||||
|
||||
// cache
|
||||
if len(node.CacheDiskDir) > 0 {
|
||||
result.HasCacheInfo = true
|
||||
} else {
|
||||
var diskCapacity = node.DecodeMaxCacheDiskCapacity()
|
||||
var memoryCapacity = node.DecodeMaxCacheMemoryCapacity()
|
||||
if (diskCapacity != nil && diskCapacity.IsNotEmpty()) || (memoryCapacity != nil && memoryCapacity.IsNotEmpty()) {
|
||||
result.HasCacheInfo = true
|
||||
}
|
||||
}
|
||||
|
||||
// thresholds
|
||||
countThresholds, err := models.SharedNodeThresholdDAO.CountAllEnabledThresholds(tx, nodeconfigs.NodeRoleNode, 0, req.NodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.HasThresholds = countThresholds > 0
|
||||
|
||||
// ssh
|
||||
nodeLogin, err := models.SharedNodeLoginDAO.FindEnabledNodeLoginWithNodeId(tx, nodeconfigs.NodeRoleNode, req.NodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nodeLogin != nil {
|
||||
sshParams, err := nodeLogin.DecodeSSHParams()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if sshParams != nil {
|
||||
result.HasSSH = len(sshParams.Host) > 0 || sshParams.Port > 0
|
||||
}
|
||||
}
|
||||
|
||||
// systemSettings
|
||||
if node.MaxCPU > 0 {
|
||||
result.HasSystemSettings = true
|
||||
} else {
|
||||
// dns resolver
|
||||
var dnsResolverConfig = node.DecodeDNSResolver()
|
||||
if dnsResolverConfig != nil {
|
||||
result.HasSystemSettings = dnsResolverConfig.Type != nodeconfigs.DNSResolverTypeDefault
|
||||
}
|
||||
}
|
||||
|
||||
// ddos protection
|
||||
result.HasDDoSProtection = node.HasDDoSProtection()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -83,7 +84,7 @@ func (this *NodeClusterService) UpdateNodeCluster(ctx context.Context, req *pb.U
|
||||
|
||||
tx := this.NullTx()
|
||||
|
||||
err = models.SharedNodeClusterDAO.UpdateCluster(tx, req.NodeClusterId, req.Name, req.NodeGrantId, req.InstallDir, req.TimeZone, req.NodeMaxThreads, req.NodeTCPMaxConnections, req.AutoOpenPorts)
|
||||
err = models.SharedNodeClusterDAO.UpdateCluster(tx, req.NodeClusterId, req.Name, req.NodeGrantId, req.InstallDir, req.TimeZone, req.NodeMaxThreads, req.AutoOpenPorts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -148,22 +149,21 @@ func (this *NodeClusterService) FindEnabledNodeCluster(ctx context.Context, req
|
||||
}
|
||||
|
||||
return &pb.FindEnabledNodeClusterResponse{NodeCluster: &pb.NodeCluster{
|
||||
Id: int64(cluster.Id),
|
||||
Name: cluster.Name,
|
||||
CreatedAt: int64(cluster.CreatedAt),
|
||||
InstallDir: cluster.InstallDir,
|
||||
NodeGrantId: int64(cluster.GrantId),
|
||||
UniqueId: cluster.UniqueId,
|
||||
Secret: cluster.Secret,
|
||||
HttpCachePolicyId: int64(cluster.CachePolicyId),
|
||||
HttpFirewallPolicyId: int64(cluster.HttpFirewallPolicyId),
|
||||
DnsName: cluster.DnsName,
|
||||
DnsDomainId: int64(cluster.DnsDomainId),
|
||||
IsOn: cluster.IsOn,
|
||||
TimeZone: cluster.TimeZone,
|
||||
NodeMaxThreads: int32(cluster.NodeMaxThreads),
|
||||
NodeTCPMaxConnections: int32(cluster.NodeTCPMaxConnections),
|
||||
AutoOpenPorts: cluster.AutoOpenPorts == 1,
|
||||
Id: int64(cluster.Id),
|
||||
Name: cluster.Name,
|
||||
CreatedAt: int64(cluster.CreatedAt),
|
||||
InstallDir: cluster.InstallDir,
|
||||
NodeGrantId: int64(cluster.GrantId),
|
||||
UniqueId: cluster.UniqueId,
|
||||
Secret: cluster.Secret,
|
||||
HttpCachePolicyId: int64(cluster.CachePolicyId),
|
||||
HttpFirewallPolicyId: int64(cluster.HttpFirewallPolicyId),
|
||||
DnsName: cluster.DnsName,
|
||||
DnsDomainId: int64(cluster.DnsDomainId),
|
||||
IsOn: cluster.IsOn,
|
||||
TimeZone: cluster.TimeZone,
|
||||
NodeMaxThreads: int32(cluster.NodeMaxThreads),
|
||||
AutoOpenPorts: cluster.AutoOpenPorts == 1,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
@@ -1054,6 +1054,9 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
|
||||
}
|
||||
}
|
||||
|
||||
// ddos
|
||||
result.HasDDoSProtection = cluster.HasDDoSProtection()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -1114,3 +1117,51 @@ func (this *NodeClusterService) UpdateNodeClusterWebPPolicy(ctx context.Context,
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindNodeClusterDDoSProtection 获取集群的DDOS设置
|
||||
func (this *NodeClusterService) FindNodeClusterDDoSProtection(ctx context.Context, req *pb.FindNodeClusterDDoSProtectionRequest) (*pb.FindNodeClusterDDoSProtectionResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
ddosProtection, err := models.SharedNodeClusterDAO.FindClusterDDoSProtection(tx, req.NodeClusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ddosProtection == nil {
|
||||
ddosProtection = ddosconfigs.DefaultProtectionConfig()
|
||||
}
|
||||
ddosProtectionJSON, err := json.Marshal(ddosProtection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result = &pb.FindNodeClusterDDoSProtectionResponse{
|
||||
DdosProtectionJSON: ddosProtectionJSON,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateNodeClusterDDoSProtection 修改集群的DDOS设置
|
||||
func (this *NodeClusterService) UpdateNodeClusterDDoSProtection(ctx context.Context, req *pb.UpdateNodeClusterDDoSProtectionRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ddosProtection = &ddosconfigs.ProtectionConfig{}
|
||||
err = json.Unmarshal(req.DdosProtectionJSON, ddosProtection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
err = models.SharedNodeClusterDAO.UpdateClusterDDoSProtection(tx, req.NodeClusterId, ddosProtection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
@@ -27,12 +27,39 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
|
||||
}
|
||||
|
||||
var pbCities = []*pb.RegionCity{}
|
||||
|
||||
var provincesMap = map[int64]*regions.RegionProvince{} // provinceId => RegionProvince
|
||||
|
||||
for _, city := range cities {
|
||||
var provinceId = int64(city.ProvinceId)
|
||||
|
||||
var pbProvince = &pb.RegionProvince{Id: provinceId}
|
||||
if req.IncludeRegionProvince {
|
||||
province, ok := provincesMap[provinceId]
|
||||
if !ok {
|
||||
province, err = regions.SharedRegionProvinceDAO.FindEnabledRegionProvince(tx, provinceId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if province == nil {
|
||||
continue
|
||||
}
|
||||
provincesMap[provinceId] = province
|
||||
}
|
||||
|
||||
pbProvince = &pb.RegionProvince{
|
||||
Id: int64(province.Id),
|
||||
Name: province.Name,
|
||||
Codes: province.DecodeCodes(),
|
||||
}
|
||||
}
|
||||
|
||||
pbCities = append(pbCities, &pb.RegionCity{
|
||||
Id: int64(city.Id),
|
||||
Name: city.Name,
|
||||
Codes: city.DecodeCodes(),
|
||||
RegionProvinceId: int64(city.ProvinceId),
|
||||
RegionProvince: pbProvince,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
@@ -154,7 +153,7 @@ func (this *ServerService) CreateServer(ctx context.Context, req *pb.CreateServe
|
||||
}
|
||||
}
|
||||
|
||||
serverId, err := models.SharedServerDAO.CreateServer(tx, req.AdminId, req.UserId, req.Type, req.Name, req.Description, serverNamesJSON, isAuditing, auditingServerNamesJSON, req.HttpJSON, req.HttpsJSON, req.TcpJSON, req.TlsJSON, req.UnixJSON, req.UdpJSON, req.WebId, req.ReverseProxyJSON, req.NodeClusterId, string(req.IncludeNodesJSON), string(req.ExcludeNodesJSON), req.ServerGroupIds, req.UserPlanId)
|
||||
serverId, err := models.SharedServerDAO.CreateServer(tx, req.AdminId, req.UserId, req.Type, req.Name, req.Description, serverNamesJSON, isAuditing, auditingServerNamesJSON, req.HttpJSON, req.HttpsJSON, req.TcpJSON, req.TlsJSON, req.UnixJSON, req.UdpJSON, req.WebId, req.ReverseProxyJSON, req.NodeClusterId, req.IncludeNodesJSON, req.ExcludeNodesJSON, req.ServerGroupIds, req.UserPlanId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1710,79 +1709,88 @@ func (this *ServerService) PurgeServerCache(ctx context.Context, req *pb.PurgeSe
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Domains) == 0 {
|
||||
return nil, errors.New("'domains' field is required")
|
||||
}
|
||||
|
||||
if len(req.Keys) == 0 && len(req.Prefixes) == 0 {
|
||||
return &pb.PurgeServerCacheResponse{IsOk: true}, nil
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
var cacheMap = utils.NewCacheMap()
|
||||
var purgeResponse = &pb.PurgeServerCacheResponse{}
|
||||
|
||||
for _, domain := range req.Domains {
|
||||
servers, err := models.SharedServerDAO.FindAllEnabledServersWithDomain(tx, domain)
|
||||
var tx = this.NullTx()
|
||||
|
||||
var taskType = "purge"
|
||||
|
||||
var tasks = []*pb.CreateHTTPCacheTaskRequest{}
|
||||
if len(req.Keys) > 0 {
|
||||
tasks = append(tasks, &pb.CreateHTTPCacheTaskRequest{
|
||||
Type: taskType,
|
||||
KeyType: "key",
|
||||
Keys: req.Keys,
|
||||
})
|
||||
}
|
||||
if len(req.Prefixes) > 0 {
|
||||
tasks = append(tasks, &pb.CreateHTTPCacheTaskRequest{
|
||||
Type: taskType,
|
||||
KeyType: "prefix",
|
||||
Keys: req.Prefixes,
|
||||
})
|
||||
}
|
||||
|
||||
var domainMap = map[string]*models.Server{} // domain name => *Server
|
||||
|
||||
for _, pbTask := range tasks {
|
||||
// 创建任务
|
||||
taskId, err := models.SharedHTTPCacheTaskDAO.CreateTask(tx, 0, pbTask.Type, pbTask.KeyType, "调用PURGE API")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, server := range servers {
|
||||
clusterId := int64(server.ClusterId)
|
||||
if clusterId > 0 {
|
||||
nodeIds, err := models.SharedNodeDAO.FindAllEnabledNodeIdsWithClusterId(tx, clusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var countKeys = 0
|
||||
|
||||
cachePolicyId, err := models.SharedNodeClusterDAO.FindClusterHTTPCachePolicyId(tx, clusterId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cachePolicyId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
cachePolicy, err := models.SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, cachePolicyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cachePolicy == nil {
|
||||
continue
|
||||
}
|
||||
cachePolicyJSON, err := json.Marshal(cachePolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, nodeId := range nodeIds {
|
||||
msg := &messageconfigs.PurgeCacheMessage{
|
||||
CachePolicyJSON: cachePolicyJSON,
|
||||
}
|
||||
if len(req.Prefixes) > 0 {
|
||||
msg.Type = messageconfigs.PurgeCacheMessageTypeDir
|
||||
msg.Keys = req.Prefixes
|
||||
} else {
|
||||
msg.Type = messageconfigs.PurgeCacheMessageTypeFile
|
||||
msg.Keys = req.Keys
|
||||
}
|
||||
msgJSON, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := SendCommandToNode(nodeId, NextCommandRequestId(), messageconfigs.MessageCodePurgeCache, msgJSON, 10, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !resp.IsOk {
|
||||
purgeResponse.IsOk = false
|
||||
purgeResponse.Message = resp.Message
|
||||
return purgeResponse, nil
|
||||
}
|
||||
}
|
||||
for _, key := range req.Keys {
|
||||
if len(key) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取域名
|
||||
var domain = utils.ParseDomainFromKey(key)
|
||||
if len(domain) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 查询所在集群
|
||||
server, ok := domainMap[domain]
|
||||
if !ok {
|
||||
server, err = models.SharedServerDAO.FindEnabledServerWithDomain(tx, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if server == nil {
|
||||
continue
|
||||
}
|
||||
domainMap[domain] = server
|
||||
}
|
||||
|
||||
var serverClusterId = int64(server.ClusterId)
|
||||
if serverClusterId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = models.SharedHTTPCacheTaskKeyDAO.CreateKey(tx, taskId, key, pbTask.Type, pbTask.KeyType, serverClusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
countKeys++
|
||||
}
|
||||
|
||||
if countKeys == 0 {
|
||||
// 如果没有有效的Key,则直接完成
|
||||
err = models.SharedHTTPCacheTaskDAO.UpdateTaskStatus(tx, taskId, true, true)
|
||||
} else {
|
||||
err = models.SharedHTTPCacheTaskDAO.UpdateTaskReady(tx, taskId)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1955,9 +1963,11 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
|
||||
DayTo: userPlan.DayTo,
|
||||
User: nil,
|
||||
Plan: &pb.Plan{
|
||||
Id: int64(plan.Id),
|
||||
Name: plan.Name,
|
||||
PriceType: plan.PriceType,
|
||||
Id: int64(plan.Id),
|
||||
Name: plan.Name,
|
||||
PriceType: plan.PriceType,
|
||||
TrafficPriceJSON: plan.TrafficPrice,
|
||||
TrafficLimitJSON: plan.TrafficLimit,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"math"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -224,12 +225,22 @@ func (this *ServerDailyStatService) FindLatestServerDailyStats(ctx context.Conte
|
||||
|
||||
// SumCurrentServerDailyStats 查找单个服务当前统计数据
|
||||
func (this *ServerDailyStatService) SumCurrentServerDailyStats(ctx context.Context, req *pb.SumCurrentServerDailyStatsRequest) (*pb.SumCurrentServerDailyStatsResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx, 0)
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx *dbs.Tx
|
||||
var tx *dbs.Tx = this.NullTx()
|
||||
|
||||
// 检查用户
|
||||
if userId > 0 {
|
||||
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 按日
|
||||
stat, err := models.SharedServerDailyStatDAO.SumCurrentDailyStat(tx, req.ServerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -250,7 +261,97 @@ func (this *ServerDailyStatService) SumCurrentServerDailyStats(ctx context.Conte
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.SumCurrentServerDailyStatsResponse{
|
||||
ServerDailyStat: pbStat,
|
||||
}, nil
|
||||
return &pb.SumCurrentServerDailyStatsResponse{ServerDailyStat: pbStat}, nil
|
||||
}
|
||||
|
||||
// SumServerDailyStats 计算单个服务的日统计
|
||||
func (this *ServerDailyStatService) SumServerDailyStats(ctx context.Context, req *pb.SumServerDailyStatsRequest) (*pb.SumServerDailyStatsResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查用户
|
||||
if userId > 0 {
|
||||
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 某日统计
|
||||
var day = timeutil.Format("Ymd")
|
||||
if regexp.MustCompile(`^\d{8}$`).MatchString(req.Day) {
|
||||
day = req.Day
|
||||
}
|
||||
|
||||
stat, err := models.SharedServerDailyStatDAO.SumDailyStat(tx, req.ServerId, day)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbStat = &pb.ServerDailyStat{
|
||||
ServerId: req.ServerId,
|
||||
}
|
||||
if stat != nil {
|
||||
pbStat = &pb.ServerDailyStat{
|
||||
ServerId: req.ServerId,
|
||||
Bytes: stat.Bytes,
|
||||
CachedBytes: stat.CachedBytes,
|
||||
CountRequests: stat.CountRequests,
|
||||
CountCachedRequests: stat.CountCachedRequests,
|
||||
CountAttackRequests: stat.CountAttackRequests,
|
||||
AttackBytes: stat.AttackBytes,
|
||||
}
|
||||
}
|
||||
return &pb.SumServerDailyStatsResponse{ServerDailyStat: pbStat}, nil
|
||||
}
|
||||
|
||||
// SumServerMonthlyStats 计算单个服务的月统计
|
||||
func (this *ServerDailyStatService) SumServerMonthlyStats(ctx context.Context, req *pb.SumServerMonthlyStatsRequest) (*pb.SumServerMonthlyStatsResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查用户
|
||||
if userId > 0 {
|
||||
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 某月统计
|
||||
var month = timeutil.Format("Ym")
|
||||
if regexp.MustCompile(`^\d{6}$`).MatchString(req.Month) {
|
||||
month = req.Month
|
||||
}
|
||||
|
||||
// 按月
|
||||
stat, err := models.SharedServerDailyStatDAO.SumMonthlyStat(tx, req.ServerId, month)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbStat = &pb.ServerDailyStat{
|
||||
ServerId: req.ServerId,
|
||||
}
|
||||
if stat != nil {
|
||||
pbStat = &pb.ServerDailyStat{
|
||||
ServerId: req.ServerId,
|
||||
Bytes: stat.Bytes,
|
||||
CachedBytes: stat.CachedBytes,
|
||||
CountRequests: stat.CountRequests,
|
||||
CountCachedRequests: stat.CountCachedRequests,
|
||||
CountAttackRequests: stat.CountAttackRequests,
|
||||
AttackBytes: stat.AttackBytes,
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.SumServerMonthlyStatsResponse{ServerMonthlyStat: pbStat}, nil
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ func TestServerService_UploadServerHTTPRequestStat(t *testing.T) {
|
||||
Month: timeutil.Format("Ym"),
|
||||
RegionCities: []*pb.UploadServerHTTPRequestStatRequest_RegionCity{
|
||||
{
|
||||
ServerId: 1,
|
||||
CountryName: "中国",
|
||||
ProvinceName: "安徽省",
|
||||
CityName: "阜阳市",
|
||||
Count: 1,
|
||||
ServerId: 1,
|
||||
CountryName: "中国",
|
||||
ProvinceName: "安徽省",
|
||||
CityName: "阜阳市",
|
||||
CountRequests: 1,
|
||||
},
|
||||
},
|
||||
RegionProviders: []*pb.UploadServerHTTPRequestStatRequest_RegionProvider{
|
||||
|
||||
@@ -2,11 +2,14 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserNodeService struct {
|
||||
@@ -259,9 +262,18 @@ func (this *UserNodeService) UpdateUserNodeStatus(ctx context.Context, req *pb.U
|
||||
return nil, errors.New("'nodeId' should be greater than 0")
|
||||
}
|
||||
|
||||
tx := this.NullTx()
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedUserNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON)
|
||||
// 修改时间戳
|
||||
var nodeStatus = &nodeconfigs.NodeStatus{}
|
||||
err = json.Unmarshal(req.StatusJSON, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode node status json failed: " + err.Error())
|
||||
}
|
||||
nodeStatus.UpdatedAt = time.Now().Unix()
|
||||
|
||||
// 保存
|
||||
err = models.SharedUserNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -75,6 +75,9 @@ var upgradeFuncs = []*upgradeVersion{
|
||||
{
|
||||
"0.4.7", upgradeV0_4_7,
|
||||
},
|
||||
{
|
||||
"0.4.8", upgradeV0_4_8,
|
||||
},
|
||||
}
|
||||
|
||||
// UpgradeSQLData 升级SQL数据
|
||||
@@ -672,3 +675,55 @@ func upgradeV0_4_7(db *dbs.DB) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// v0.4.7
|
||||
func upgradeV0_4_8(db *dbs.DB) error {
|
||||
// 设置edgeIPLists中的serverId
|
||||
{
|
||||
firewallPolicyOnes, _, err := db.FindOnes("SELECT inbound,serverId FROM edgeHTTPFirewallPolicies WHERE serverId>0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, one := range firewallPolicyOnes {
|
||||
var inboundBytes = one.GetBytes("inbound")
|
||||
var serverId = one.GetInt64("serverId")
|
||||
|
||||
var listIds = []int64{}
|
||||
|
||||
if len(inboundBytes) > 0 {
|
||||
var inbound = &firewallconfigs.HTTPFirewallInboundConfig{}
|
||||
err = json.Unmarshal(inboundBytes, inbound)
|
||||
if err == nil { // we ignore errors
|
||||
if inbound.AllowListRef != nil && inbound.AllowListRef.ListId > 0 {
|
||||
listIds = append(listIds, inbound.AllowListRef.ListId)
|
||||
}
|
||||
if inbound.DenyListRef != nil && inbound.DenyListRef.ListId > 0 {
|
||||
listIds = append(listIds, inbound.DenyListRef.ListId)
|
||||
}
|
||||
if inbound.GreyListRef != nil && inbound.GreyListRef.ListId > 0 {
|
||||
listIds = append(listIds, inbound.GreyListRef.ListId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(listIds) == 0 {
|
||||
continue
|
||||
}
|
||||
for _, listId := range listIds {
|
||||
isPublicCol, err := db.FindCol(0, "SELECT isPublic FROM edgeIPLists WHERE id=? LIMIT 1", listId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var isPublic = types.Bool(isPublicCol)
|
||||
if !isPublic {
|
||||
_, err = db.Exec("UPDATE edgeIPLists SET serverId=? WHERE id=?", serverId, listId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -175,3 +175,22 @@ func TestUpgradeSQLData_v0_4_7(t *testing.T) {
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestUpgradeSQLData_v0_4_8(t *testing.T) {
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = db.Close()
|
||||
}()
|
||||
err = upgradeV0_4_8(db)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func (this *HealthCheckExecutor) Run() ([]*HealthCheckResult, error) {
|
||||
}
|
||||
|
||||
var results = []*HealthCheckResult{}
|
||||
nodes, err := models.NewNodeDAO().FindAllEnabledNodesWithClusterId(nil, this.clusterId)
|
||||
nodes, err := models.NewNodeDAO().FindAllEnabledNodesWithClusterId(nil, this.clusterId, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -234,6 +234,7 @@ func (this *HealthCheckExecutor) runNodeOnce(healthCheckConfig *serverconfigs.He
|
||||
|
||||
key, err := nodeutils.Base64EncodeMap(maps.Map{
|
||||
"onlyBasicRequest": healthCheckConfig.OnlyBasicRequest,
|
||||
"accessLogIsOn": healthCheckConfig.AccessLogIsOn,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -72,7 +72,7 @@ func (this *HealthCheckTask) Loop() error {
|
||||
for _, cluster := range clusters {
|
||||
clusterId := int64(cluster.Id)
|
||||
|
||||
config := &serverconfigs.HealthCheckConfig{}
|
||||
var config = &serverconfigs.HealthCheckConfig{}
|
||||
if len(cluster.HealthCheck) > 0 {
|
||||
err = json.Unmarshal(cluster.HealthCheck, config)
|
||||
if err != nil {
|
||||
|
||||
26
internal/utils/domain.go
Normal file
26
internal/utils/domain.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cacheKeyDomainReg1 = regexp.MustCompile(`^(?i)(?:http|https)://([\w-.]+)`)
|
||||
var cacheKeyDomainReg2 = regexp.MustCompile(`^([\w-.]+)`)
|
||||
|
||||
// ParseDomainFromKey 从Key中获取域名
|
||||
func ParseDomainFromKey(key string) (domain string) {
|
||||
var pieces = cacheKeyDomainReg1.FindStringSubmatch(key)
|
||||
if len(pieces) > 1 {
|
||||
return strings.ToLower(pieces[1])
|
||||
}
|
||||
|
||||
pieces = cacheKeyDomainReg2.FindStringSubmatch(key)
|
||||
if len(pieces) > 1 {
|
||||
return strings.ToLower(pieces[1])
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
package sizes_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/utils/sizes"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/sizes"
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user