mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-05 01:20:25 +08:00
DNSPod和Alidns记录信息增加缓存
This commit is contained in:
@@ -356,7 +356,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
|
|||||||
errMsg = "找不到DNS服务商账号"
|
errMsg = "找不到DNS服务商账号"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
providerInterface := dnsclients.FindProvider(dnsProvider.Type)
|
providerInterface := dnsclients.FindProvider(dnsProvider.Type, int64(dnsProvider.Id))
|
||||||
if providerInterface == nil {
|
if providerInterface == nil {
|
||||||
errMsg = "暂不支持此类型的DNS服务商 '" + dnsProvider.Type + "'"
|
errMsg = "暂不支持此类型的DNS服务商 '" + dnsProvider.Type + "'"
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var dnsProvider = dnsclients.FindProvider(provider.Type)
|
var dnsProvider = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if dnsProvider == nil {
|
if dnsProvider == nil {
|
||||||
issues = append(issues, &pb.DNSIssue{
|
issues = append(issues, &pb.DNSIssue{
|
||||||
Target: cluster.Name,
|
Target: cluster.Name,
|
||||||
@@ -200,7 +200,7 @@ func FindDefaultDomainRoute(tx *dbs.Tx, domain *dns.DNSDomain) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("decode provider params failed: " + err.Error())
|
return "", errors.New("decode provider params failed: " + err.Error())
|
||||||
}
|
}
|
||||||
var dnsProvider = dnsclients.FindProvider(provider.Type)
|
var dnsProvider = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if dnsProvider == nil {
|
if dnsProvider == nil {
|
||||||
return "", errors.New("not supported provider type '" + provider.Type + "'")
|
return "", errors.New("not supported provider type '" + provider.Type + "'")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,3 +141,12 @@ func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (
|
|||||||
Result("version").
|
Result("version").
|
||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 读取当前版本号
|
||||||
|
func (this *SysLockerDAO) Read(tx *dbs.Tx, key string) (int64, error) {
|
||||||
|
return this.Query(tx).
|
||||||
|
Attr("key", key).
|
||||||
|
Result("version").
|
||||||
|
FindInt64Col(0)
|
||||||
|
}
|
||||||
@@ -17,3 +17,26 @@ type Record struct {
|
|||||||
Route string `json:"route"`
|
Route string `json:"route"`
|
||||||
TTL int32 `json:"ttl"`
|
TTL int32 `json:"ttl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Record) Clone() *Record {
|
||||||
|
return &Record{
|
||||||
|
Id: this.Id,
|
||||||
|
Name: this.Name,
|
||||||
|
Type: this.Type,
|
||||||
|
Value: this.Value,
|
||||||
|
Route: this.Route,
|
||||||
|
TTL: this.TTL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Record) Copy(anotherRecord *Record) {
|
||||||
|
if anotherRecord == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Id = anotherRecord.Id
|
||||||
|
this.Name = anotherRecord.Name
|
||||||
|
this.Type = anotherRecord.Type
|
||||||
|
this.Value = anotherRecord.Value
|
||||||
|
this.Route = anotherRecord.Route
|
||||||
|
this.TTL = anotherRecord.TTL
|
||||||
|
}
|
||||||
|
|||||||
202
internal/dnsclients/domain_records_cache.go
Normal file
202
internal/dnsclients/domain_records_cache.go
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package dnsclients
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
go func() {
|
||||||
|
var ticker = time.NewTicker(1 * time.Hour)
|
||||||
|
for range ticker.C {
|
||||||
|
sharedDomainRecordsCache.Clean()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type recordList struct {
|
||||||
|
version int64
|
||||||
|
updatedAt int64
|
||||||
|
records []*dnstypes.Record
|
||||||
|
}
|
||||||
|
|
||||||
|
var sharedDomainRecordsCache = NewDomainRecordsCache()
|
||||||
|
|
||||||
|
// DomainRecordsCache 域名记录缓存
|
||||||
|
// TODO 自动清理没有使用的域名记录,以节约内存
|
||||||
|
type DomainRecordsCache struct {
|
||||||
|
domainRecordsMap map[string]*recordList // domain@providerId => record
|
||||||
|
locker sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDomainRecordsCache() *DomainRecordsCache {
|
||||||
|
return &DomainRecordsCache{
|
||||||
|
domainRecordsMap: map[string]*recordList{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteDomainRecords 写入域名记录缓存
|
||||||
|
func (this *DomainRecordsCache) WriteDomainRecords(providerId int64, domain string, records []*dnstypes.Record) {
|
||||||
|
if providerId <= 0 || len(domain) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domain = types.String(providerId) + "@" + domain
|
||||||
|
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
// 版本号
|
||||||
|
var key = "DomainRecordsCache" + "@" + types.String(providerId) + "@" + domain
|
||||||
|
version, err := models.SharedSysLockerDAO.Increase(nil, key, 1)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("dnsclients.BaseProvider", "WriteDomainRecordsCache: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var clonedRecords = []*dnstypes.Record{}
|
||||||
|
for _, record := range records {
|
||||||
|
clonedRecords = append(clonedRecords, record)
|
||||||
|
}
|
||||||
|
this.domainRecordsMap[domain] = &recordList{
|
||||||
|
version: version,
|
||||||
|
updatedAt: time.Now().Unix(),
|
||||||
|
records: clonedRecords,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryDomainRecord 从缓存中读取域名记录
|
||||||
|
func (this *DomainRecordsCache) QueryDomainRecord(providerId int64, domain string, recordName string, recordType string) (record *dnstypes.Record, hasRecords bool, ok bool) {
|
||||||
|
if providerId <= 0 || len(domain) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domain = types.String(providerId) + "@" + domain
|
||||||
|
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
// check version
|
||||||
|
var key = "DomainRecordsCache" + "@" + types.String(providerId) + "@" + domain
|
||||||
|
version, err := models.SharedSysLockerDAO.Read(nil, key)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("dnsclients.BaseProvider", "ReadDomainRecordsCache: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// find list
|
||||||
|
list, recordsOk := this.domainRecordsMap[domain]
|
||||||
|
if !recordsOk {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if version != list.version {
|
||||||
|
delete(this.domainRecordsMap, domain)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check timestamp
|
||||||
|
if list.updatedAt < time.Now().Unix()-86400 /** 缓存有效期为一天 **/ {
|
||||||
|
delete(this.domainRecordsMap, domain)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hasRecords = true
|
||||||
|
for _, r := range list.records {
|
||||||
|
if r.Name == recordName && r.Type == recordType {
|
||||||
|
return r, true, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDomainRecord 删除域名记录缓存
|
||||||
|
func (this *DomainRecordsCache) DeleteDomainRecord(providerId int64, domain string, recordId string) {
|
||||||
|
if providerId <= 0 || len(domain) == 0 || len(recordId) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domain = types.String(providerId) + "@" + domain
|
||||||
|
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
list, ok := this.domainRecordsMap[domain]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var found = false
|
||||||
|
var newRecords = []*dnstypes.Record{}
|
||||||
|
for _, record := range list.records {
|
||||||
|
if record.Id == recordId {
|
||||||
|
found = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newRecords = append(newRecords, record)
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
list.records = newRecords
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDomainRecord 添加域名记录缓存
|
||||||
|
func (this *DomainRecordsCache) AddDomainRecord(providerId int64, domain string, record *dnstypes.Record) {
|
||||||
|
if providerId <= 0 || len(domain) == 0 || record == nil || len(record.Id) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domain = types.String(providerId) + "@" + domain
|
||||||
|
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
list, ok := this.domainRecordsMap[domain]
|
||||||
|
if ok {
|
||||||
|
list.records = append(list.records, record.Clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果完全没有记录,则不保存
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDomainRecord 修改域名记录缓存
|
||||||
|
func (this *DomainRecordsCache) UpdateDomainRecord(providerId int64, domain string, record *dnstypes.Record) {
|
||||||
|
if providerId <= 0 || len(domain) == 0 || record == nil || len(record.Id) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domain = types.String(providerId) + "@" + domain
|
||||||
|
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
list, ok := this.domainRecordsMap[domain]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, r := range list.records {
|
||||||
|
if r.Id == record.Id {
|
||||||
|
r.Copy(record)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean 清除过期缓存
|
||||||
|
func (this *DomainRecordsCache) Clean() {
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
for domain, list := range this.domainRecordsMap {
|
||||||
|
if list.updatedAt < time.Now().Unix()-86400 {
|
||||||
|
delete(this.domainRecordsMap, domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
internal/dnsclients/domain_records_cahce_test.go
Normal file
58
internal/dnsclients/domain_records_cahce_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package dnsclients_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDomainRecordsCache_WriteDomainRecords(t *testing.T) {
|
||||||
|
dbs.NotifyReady()
|
||||||
|
|
||||||
|
var cache = dnsclients.NewDomainRecordsCache()
|
||||||
|
cache.WriteDomainRecords(1, "a", []*dnstypes.Record{
|
||||||
|
{
|
||||||
|
Id: "1",
|
||||||
|
Name: "hello",
|
||||||
|
Type: "A",
|
||||||
|
Value: "192.168.1.100",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
//time.Sleep(30 * time.Second)
|
||||||
|
|
||||||
|
{
|
||||||
|
t.Log(cache.QueryDomainRecord(1, "a", "hello", "A"))
|
||||||
|
}
|
||||||
|
{
|
||||||
|
t.Log(cache.QueryDomainRecord(1, "a", "hello", "AAAA"))
|
||||||
|
}
|
||||||
|
{
|
||||||
|
t.Log(cache.QueryDomainRecord(1, "a", "hello2", "A"))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("======")
|
||||||
|
cache.DeleteDomainRecord(1, "a", "2")
|
||||||
|
cache.UpdateDomainRecord(1, "a", &dnstypes.Record{
|
||||||
|
Id: "1",
|
||||||
|
Name: "hello2",
|
||||||
|
Type: "A",
|
||||||
|
Value: "192.168.1.200",
|
||||||
|
})
|
||||||
|
{
|
||||||
|
t.Log(cache.QueryDomainRecord(1, "a", "hello2", "A"))
|
||||||
|
}
|
||||||
|
t.Log("======")
|
||||||
|
cache.AddDomainRecord(1, "a", &dnstypes.Record{
|
||||||
|
Id: "2",
|
||||||
|
Name: "hello",
|
||||||
|
Type: "AAAA",
|
||||||
|
Value: "::1",
|
||||||
|
})
|
||||||
|
{
|
||||||
|
t.Log(cache.QueryDomainRecord(1, "a", "hello", "AAAA"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ import (
|
|||||||
type AliDNSProvider struct {
|
type AliDNSProvider struct {
|
||||||
BaseProvider
|
BaseProvider
|
||||||
|
|
||||||
|
ProviderId int64
|
||||||
|
|
||||||
accessKeyId string
|
accessKeyId string
|
||||||
accessKeySecret string
|
accessKeySecret string
|
||||||
regionId string
|
regionId string
|
||||||
@@ -106,6 +108,11 @@ func (this *AliDNSProvider) GetRecords(domain string) (records []*dnstypes.Recor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 写入缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.WriteDomainRecords(this.ProviderId, domain, records)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +137,14 @@ func (this *AliDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
|
|||||||
|
|
||||||
// QueryRecord 查询单个记录
|
// QueryRecord 查询单个记录
|
||||||
func (this *AliDNSProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
|
func (this *AliDNSProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
|
||||||
|
// 从缓存中读取
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
|
||||||
|
if hasRecords { // 有效的搜索
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
records, err := this.GetRecords(domain)
|
records, err := this.GetRecords(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -162,6 +177,12 @@ func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record)
|
|||||||
}
|
}
|
||||||
if resp.IsSuccess() {
|
if resp.IsSuccess() {
|
||||||
newRecord.Id = resp.RecordId
|
newRecord.Id = resp.RecordId
|
||||||
|
|
||||||
|
// 加入缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.AddDomainRecord(this.ProviderId, domain, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,9 +204,20 @@ func (this *AliDNSProvider) UpdateRecord(domain string, record *dnstypes.Record,
|
|||||||
|
|
||||||
var resp = alidns.CreateUpdateDomainRecordResponse()
|
var resp = alidns.CreateUpdateDomainRecordResponse()
|
||||||
err := this.doAPI(req, resp)
|
err := this.doAPI(req, resp)
|
||||||
|
if err != nil {
|
||||||
return this.WrapError(err, domain, newRecord)
|
return this.WrapError(err, domain, newRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newRecord.Id = record.Id
|
||||||
|
|
||||||
|
// 修改缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.UpdateDomainRecord(this.ProviderId, domain, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteRecord 删除记录
|
// DeleteRecord 删除记录
|
||||||
func (this *AliDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
func (this *AliDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
||||||
var req = alidns.CreateDeleteDomainRecordRequest()
|
var req = alidns.CreateDeleteDomainRecordRequest()
|
||||||
@@ -193,9 +225,18 @@ func (this *AliDNSProvider) DeleteRecord(domain string, record *dnstypes.Record)
|
|||||||
|
|
||||||
var resp = alidns.CreateDeleteDomainRecordResponse()
|
var resp = alidns.CreateDeleteDomainRecordResponse()
|
||||||
err := this.doAPI(req, resp)
|
err := this.doAPI(req, resp)
|
||||||
|
if err != nil {
|
||||||
return this.WrapError(err, domain, record)
|
return this.WrapError(err, domain, record)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.DeleteDomainRecord(this.ProviderId, domain, record.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultRoute 默认线路
|
// DefaultRoute 默认线路
|
||||||
func (this *AliDNSProvider) DefaultRoute() string {
|
func (this *AliDNSProvider) DefaultRoute() string {
|
||||||
return "default"
|
return "default"
|
||||||
|
|||||||
@@ -32,6 +32,27 @@ func TestAliDNSProvider_GetRecords(t *testing.T) {
|
|||||||
logs.PrintAsJSON(records, t)
|
logs.PrintAsJSON(records, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAliDNSProvider_QueryRecord(t *testing.T) {
|
||||||
|
provider, err := testAliDNSProvider()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
record, err := provider.QueryRecord("meloy.cn", "www", "A")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(record)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
record, err := provider.QueryRecord("meloy.cn", "www1", "A")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(record)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAliDNSProvider_DeleteRecord(t *testing.T) {
|
func TestAliDNSProvider_DeleteRecord(t *testing.T) {
|
||||||
provider, err := testAliDNSProvider()
|
provider, err := testAliDNSProvider()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -100,6 +121,8 @@ func TestAliDNSProvider_UpdateRecord(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testAliDNSProvider() (ProviderInterface, error) {
|
func testAliDNSProvider() (ProviderInterface, error) {
|
||||||
|
dbs.NotifyReady()
|
||||||
|
|
||||||
db, err := dbs.Default()
|
db, err := dbs.Default()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -113,7 +136,9 @@ func testAliDNSProvider() (ProviderInterface, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
provider := &AliDNSProvider{}
|
provider := &AliDNSProvider{
|
||||||
|
ProviderId: one.GetInt64("id"),
|
||||||
|
}
|
||||||
err = provider.Auth(apiParams)
|
err = provider.Auth(apiParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BaseProvider struct {
|
type BaseProvider struct{}
|
||||||
}
|
|
||||||
|
|
||||||
// WrapError 封装解析相关错误
|
// WrapError 封装解析相关错误
|
||||||
func (this *BaseProvider) WrapError(err error, domain string, record *dnstypes.Record) error {
|
func (this *BaseProvider) WrapError(err error, domain string, record *dnstypes.Record) error {
|
||||||
@@ -27,4 +26,3 @@ func (this *BaseProvider) WrapError(err error, domain string, record *dnstypes.R
|
|||||||
}
|
}
|
||||||
return errors.New("record operation failed: '" + fullname + " " + record.Type + " " + record.Value + " " + types.String(record.TTL) + "': " + err.Error())
|
return errors.New("record operation failed: '" + fullname + " " + record.Type + " " + record.Value + " " + types.String(record.TTL) + "': " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ var cloudFlareHTTPClient = &http.Client{
|
|||||||
type CloudFlareProvider struct {
|
type CloudFlareProvider struct {
|
||||||
BaseProvider
|
BaseProvider
|
||||||
|
|
||||||
|
ProviderId int64
|
||||||
|
|
||||||
apiKey string // API密钥
|
apiKey string // API密钥
|
||||||
email string // 账号邮箱
|
email string // 账号邮箱
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ type CustomHTTPProvider struct {
|
|||||||
url string
|
url string
|
||||||
secret string
|
secret string
|
||||||
|
|
||||||
|
ProviderId int64
|
||||||
|
|
||||||
BaseProvider
|
BaseProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ var dnsPodHTTPClient = &http.Client{
|
|||||||
type DNSPodProvider struct {
|
type DNSPodProvider struct {
|
||||||
BaseProvider
|
BaseProvider
|
||||||
|
|
||||||
|
ProviderId int64
|
||||||
|
|
||||||
region string
|
region string
|
||||||
apiId string
|
apiId string
|
||||||
apiToken string
|
apiToken string
|
||||||
@@ -53,6 +55,7 @@ func (this *DNSPodProvider) Auth(params maps.Map) error {
|
|||||||
if len(this.apiToken) == 0 {
|
if len(this.apiToken) == 0 {
|
||||||
return errors.New("'token' should not be empty")
|
return errors.New("'token' should not be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +123,12 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 写入缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.WriteDomainRecords(this.ProviderId, domain, records)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +169,14 @@ func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
|
|||||||
|
|
||||||
// QueryRecord 查询单个记录
|
// QueryRecord 查询单个记录
|
||||||
func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
|
func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
|
||||||
|
// 从缓存中读取
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
|
||||||
|
if hasRecords { // 有效的搜索
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
records, err := this.GetRecords(domain)
|
records, err := this.GetRecords(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -199,6 +216,12 @@ func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record)
|
|||||||
return this.WrapError(err, domain, newRecord)
|
return this.WrapError(err, domain, newRecord)
|
||||||
}
|
}
|
||||||
newRecord.Id = types.String(resp.Record.Id)
|
newRecord.Id = types.String(resp.Record.Id)
|
||||||
|
|
||||||
|
// 加入缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.AddDomainRecord(this.ProviderId, domain, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +252,20 @@ func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record,
|
|||||||
}
|
}
|
||||||
var resp = new(dnspod.RecordModifyResponse)
|
var resp = new(dnspod.RecordModifyResponse)
|
||||||
err := this.doAPI("/Record.Modify", args, resp)
|
err := this.doAPI("/Record.Modify", args, resp)
|
||||||
|
if err != nil {
|
||||||
return this.WrapError(err, domain, newRecord)
|
return this.WrapError(err, domain, newRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newRecord.Id = record.Id
|
||||||
|
|
||||||
|
// 修改缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.UpdateDomainRecord(this.ProviderId, domain, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteRecord 删除记录
|
// DeleteRecord 删除记录
|
||||||
func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
||||||
if record == nil {
|
if record == nil {
|
||||||
@@ -244,9 +278,18 @@ func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record)
|
|||||||
"record_id": record.Id,
|
"record_id": record.Id,
|
||||||
}, resp)
|
}, resp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
return this.WrapError(err, domain, record)
|
return this.WrapError(err, domain, record)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.DeleteDomainRecord(this.ProviderId, domain, record.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
func (this *DNSPodProvider) doAPI(path string, params map[string]string, respPtr dnspod.ResponseInterface) error {
|
func (this *DNSPodProvider) doAPI(path string, params map[string]string, respPtr dnspod.ResponseInterface) error {
|
||||||
var apiHost = "https://dnsapi.cn"
|
var apiHost = "https://dnsapi.cn"
|
||||||
|
|||||||
@@ -75,6 +75,29 @@ func TestDNSPodProvider_AddRecord(t *testing.T) {
|
|||||||
t.Log("ok, record id:", record.Id)
|
t.Log("ok, record id:", record.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDNSPodProvider_QueryRecord(t *testing.T) {
|
||||||
|
provider, _, err := testDNSPodProvider()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
record, err := provider.QueryRecord(DNSPodTestDomain, "hello-forward", dnstypes.RecordTypeCNAME)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
record, err := provider.QueryRecord(DNSPodTestDomain, "hello-forward2", dnstypes.RecordTypeCNAME)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(record)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNSPodProvider_UpdateRecord(t *testing.T) {
|
func TestDNSPodProvider_UpdateRecord(t *testing.T) {
|
||||||
provider, isInternational, err := testDNSPodProvider()
|
provider, isInternational, err := testDNSPodProvider()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -122,6 +145,8 @@ func TestDNSPodProvider_DeleteRecord(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testDNSPodProvider() (provider dnsclients.ProviderInterface, isInternational bool, err error) {
|
func testDNSPodProvider() (provider dnsclients.ProviderInterface, isInternational bool, err error) {
|
||||||
|
dbs.NotifyReady()
|
||||||
|
|
||||||
db, err := dbs.Default()
|
db, err := dbs.Default()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@@ -130,12 +155,14 @@ func testDNSPodProvider() (provider dnsclients.ProviderInterface, isInternationa
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
apiParams := maps.Map{}
|
var apiParams = maps.Map{}
|
||||||
err = json.Unmarshal([]byte(one.GetString("apiParams")), &apiParams)
|
err = json.Unmarshal([]byte(one.GetString("apiParams")), &apiParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
provider = &dnsclients.DNSPodProvider{}
|
provider = &dnsclients.DNSPodProvider{
|
||||||
|
ProviderId: one.GetInt64("id"),
|
||||||
|
}
|
||||||
err = provider.Auth(apiParams)
|
err = provider.Auth(apiParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ var edgeDNSHTTPClient = &http.Client{
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EdgeDNSAPIProvider struct {
|
type EdgeDNSAPIProvider struct {
|
||||||
|
BaseProvider
|
||||||
|
|
||||||
|
ProviderId int64
|
||||||
|
|
||||||
host string
|
host string
|
||||||
accessKeyId string
|
accessKeyId string
|
||||||
accessKeySecret string
|
accessKeySecret string
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ var huaweiDNSHTTPClient = &http.Client{
|
|||||||
type HuaweiDNSProvider struct {
|
type HuaweiDNSProvider struct {
|
||||||
BaseProvider
|
BaseProvider
|
||||||
|
|
||||||
|
ProviderId int64
|
||||||
|
|
||||||
accessKeyId string
|
accessKeyId string
|
||||||
accessKeySecret string
|
accessKeySecret string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,20 +7,32 @@ package dnsclients
|
|||||||
import "github.com/iwind/TeaGo/maps"
|
import "github.com/iwind/TeaGo/maps"
|
||||||
|
|
||||||
// FindProvider 查找服务商实例
|
// FindProvider 查找服务商实例
|
||||||
func FindProvider(providerType ProviderType) ProviderInterface {
|
func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {
|
||||||
switch providerType {
|
switch providerType {
|
||||||
case ProviderTypeDNSPod:
|
case ProviderTypeDNSPod:
|
||||||
return &DNSPodProvider{}
|
return &DNSPodProvider{
|
||||||
|
ProviderId: providerId,
|
||||||
|
}
|
||||||
case ProviderTypeAliDNS:
|
case ProviderTypeAliDNS:
|
||||||
return &AliDNSProvider{}
|
return &AliDNSProvider{
|
||||||
|
ProviderId: providerId,
|
||||||
|
}
|
||||||
case ProviderTypeHuaweiDNS:
|
case ProviderTypeHuaweiDNS:
|
||||||
return &HuaweiDNSProvider{}
|
return &HuaweiDNSProvider{
|
||||||
|
ProviderId: providerId,
|
||||||
|
}
|
||||||
case ProviderTypeCloudFlare:
|
case ProviderTypeCloudFlare:
|
||||||
return &CloudFlareProvider{}
|
return &CloudFlareProvider{
|
||||||
|
ProviderId: providerId,
|
||||||
|
}
|
||||||
case ProviderTypeCustomHTTP:
|
case ProviderTypeCustomHTTP:
|
||||||
return &CustomHTTPProvider{}
|
return &CustomHTTPProvider{
|
||||||
|
ProviderId: providerId,
|
||||||
|
}
|
||||||
case ProviderTypeEdgeDNSAPI:
|
case ProviderTypeEdgeDNSAPI:
|
||||||
return &EdgeDNSAPIProvider{}
|
return &EdgeDNSAPIProvider{
|
||||||
|
ProviderId: providerId,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func (this *DNSDomainService) CreateDNSDomain(ctx context.Context, req *pb.Creat
|
|||||||
goman.New(func() {
|
goman.New(func() {
|
||||||
domainName := req.Name
|
domainName := req.Name
|
||||||
|
|
||||||
providerInterface := dnsclients.FindProvider(provider.Type)
|
providerInterface := dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if providerInterface == nil {
|
if providerInterface == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -678,7 +678,7 @@ func (this *DNSDomainService) syncClusterDNS(req *pb.SyncDNSDomainDataRequest) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 开始同步
|
// 开始同步
|
||||||
var manager = dnsclients.FindProvider(provider.Type)
|
var manager = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if manager == nil {
|
if manager == nil {
|
||||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "目前不支持'" + provider.Type + "'"}, nil
|
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "目前不支持'" + provider.Type + "'"}, nil
|
||||||
}
|
}
|
||||||
@@ -816,7 +816,7 @@ func (this *DNSDomainService) SyncDNSDomainsFromProvider(ctx context.Context, re
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsProvider := dnsclients.FindProvider(provider.Type)
|
dnsProvider := dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if dnsProvider == nil {
|
if dnsProvider == nil {
|
||||||
return nil, errors.New("provider type '" + provider.Type + "' is not supported yet")
|
return nil, errors.New("provider type '" + provider.Type + "' is not supported yet")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -552,7 +552,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
|
|||||||
TypeName: dnsclients.FindProviderTypeName(provider.Type),
|
TypeName: dnsclients.FindProviderTypeName(provider.Type),
|
||||||
}
|
}
|
||||||
|
|
||||||
manager := dnsclients.FindProvider(provider.Type)
|
var manager = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if manager != nil {
|
if manager != nil {
|
||||||
apiParams, err := provider.DecodeAPIParams()
|
apiParams, err := provider.DecodeAPIParams()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ func (this *DNSTaskExecutor) doDomainWithTask(taskId int64, domainId int64) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
manager := dnsclients.FindProvider(provider.Type)
|
manager := dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if manager == nil {
|
if manager == nil {
|
||||||
this.logErr("DNSTaskExecutor", "unsupported dns provider type '"+provider.Type+"'")
|
this.logErr("DNSTaskExecutor", "unsupported dns provider type '"+provider.Type+"'")
|
||||||
isOk = true
|
isOk = true
|
||||||
@@ -717,7 +717,7 @@ func (this *DNSTaskExecutor) findDNSManagerWithDomainId(tx *dbs.Tx, domainId int
|
|||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var manager = dnsclients.FindProvider(provider.Type)
|
var manager = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if manager == nil {
|
if manager == nil {
|
||||||
this.logErr("DNSTaskExecutor", "unsupported dns provider type '"+provider.Type+"'")
|
this.logErr("DNSTaskExecutor", "unsupported dns provider type '"+provider.Type+"'")
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user