Skip to content

Commit

Permalink
Merge pull request #15 from crhstack/main
Browse files Browse the repository at this point in the history
add aws
  • Loading branch information
eryajf authored Sep 9, 2024
2 parents e3105fa + 4bb257b commit af8978e
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 1 deletion.
7 changes: 6 additions & 1 deletion config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ cloud_providers:
- name: g1
secretId: "xxxxx"
secretKey: "xxxxx"
amazon:
accounts:
- name: a1
secretId: "xxxxx"
secretKey: "xxxxx"
dnsla:
accounts:
- name: d1
secretId: "xxxxx"
secretKey: "xxxxx"
# 目前支持Tencent, Aliyun, Godaddy,DNALA,如需支持更多云厂商,请提交 issue,也欢迎 PR
# 目前支持Tencent, Aliyun, Godaddy,DNALA, Amazon,如需支持更多云厂商,请提交 issue,也欢迎 PR
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,16 @@ require (
github.com/alibabacloud-go/tea-utils/v2 v2.0.6 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/credentials-go v1.3.1 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.43.2 // indirect
github.com/aws/aws-sdk-go-v2/service/route53domains v1.25.6 // indirect
github.com/aws/smithy-go v1.20.4 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.12.1-0.20240709150035-ccf4b4329d21 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
266 changes: 266 additions & 0 deletions pkg/provider/amazon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
package provider

import (
"encoding/json"
"fmt"
"github.com/alibabacloud-go/tea/tea"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/route53"
"github.com/aws/aws-sdk-go-v2/service/route53/types"
"github.com/aws/aws-sdk-go-v2/service/route53domains"
domainTypes "github.com/aws/aws-sdk-go-v2/service/route53domains/types"
"github.com/eryajf/cloud_dns_exporter/public"
"github.com/golang-module/carbon/v2"
"golang.org/x/net/context"
"strings"
"sync"
"time"
)

type AmazonDNS struct {
account public.Account
client *route53.Client
}

const region = "us-east-1"

func NewAwsDnsClient(secretID string, secretKey string) *route53.Client {
return route53.New(route53.Options{
Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(secretID, secretKey, "")),
Region: region,
RetryMaxAttempts: 3,
})
}

func NewAwsDns(account public.Account) *AmazonDNS {
client := NewAwsDnsClient(account.SecretID, account.SecretKey)
return &AmazonDNS{
account: account,
client: client,
}
}

func NewAwsDomainClient(secretID string, secretKey string) *route53domains.Client {
return route53domains.New(route53domains.Options{
Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(secretID, secretKey, "")),
Region: region,
})
}

func (a *AmazonDNS) ListDomains() ([]Domain, error) {
ad := NewAwsDns(public.Account{
CloudProvider: a.account.CloudProvider,
CloudName: a.account.CloudName,
SecretID: a.account.SecretID,
SecretKey: a.account.SecretKey,
})
a.client = ad.client
var (
dataObj []Domain
wg sync.WaitGroup
mu sync.Mutex
)
domains, err := a.getDomainList()
if err != nil {
return nil, err
}
ticker := time.NewTicker(100 * time.Millisecond)
for _, domain := range domains {
wg.Add(1)
go func(domain types.HostedZone) {
defer wg.Done()
<-ticker.C
domainName := strings.TrimSuffix(tea.StringValue(domain.Name), ".")
domainCreateAndExpiryDate := a.getDomainCreateAndExpiryDate(domainName)
mu.Lock()
dataObj = append(dataObj, Domain{
CloudProvider: a.account.CloudProvider,
CloudName: a.account.CloudName,
DomainID: strings.TrimPrefix(tea.StringValue(domain.Id), "/hostedzone/"),
DomainName: fmt.Sprintf(domainName),
DomainRemark: tea.StringValue(nil),
DomainStatus: "enable",
CreatedDate: domainCreateAndExpiryDate.CreatedDate,
ExpiryDate: domainCreateAndExpiryDate.ExpiryDate,
DaysUntilExpiry: domainCreateAndExpiryDate.DaysUntilExpiry,
})
mu.Unlock()
}(domain)
}
wg.Wait()
return dataObj, nil
}

func (a *AmazonDNS) ListRecords() ([]Record, error) {
var (
dataObj []Record
domains []Domain
wg sync.WaitGroup
mu sync.Mutex
)
ad := NewAwsDns(public.Account{
CloudProvider: a.account.CloudProvider,
CloudName: a.account.CloudName,
SecretID: a.account.SecretID,
SecretKey: a.account.SecretKey,
})
a.client = ad.client
rst, err := public.Cache.Get(public.DomainList + "_" + a.account.CloudProvider + "_" + a.account.CloudName)
if err != nil {
return nil, err
}
err = json.Unmarshal(rst, &domains)
if err != nil {
return nil, err
}
results := make(map[string][]types.ResourceRecordSet)
ticker := time.NewTicker(100 * time.Millisecond)
for _, domain := range domains {
wg.Add(1)
// aws 接口并发限制
time.Sleep(200 * time.Millisecond)
go func(domain Domain) {
defer wg.Done()
<-ticker.C
records, err := a.getRecordList(domain.DomainID)
if err != nil {
fmt.Printf("get record list failed: %s\n", err)
}
mu.Lock()
results[domain.DomainName] = records
mu.Unlock()
}(domain)
}
wg.Wait()
for domain, record := range results {
for _, record := range record {
recordInfo := Record{
CloudProvider: a.account.CloudProvider,
CloudName: a.account.CloudName,
DomainName: domain,
RecordID: tea.StringValue(record.SetIdentifier),
RecordType: fmt.Sprintf("%s", record.Type),
RecordWeight: fmt.Sprintf("%d", record.Weight),
RecordStatus: oneStatus("enable"),
RecordRemark: tea.StringValue(nil),
UpdateTime: carbon.CreateFromTimestampMilli(tea.Int64Value(nil)).ToDateTimeString(),
FullRecord: strings.TrimSuffix(tea.StringValue(record.Name), "."),
}
// aws域名返回完整域名处理
recordName := strings.TrimSuffix(tea.StringValue(record.Name), ".")
if len(strings.Split(recordName, ".")) > 2 {
recordInfo.RecordName = strings.TrimSuffix(strings.Replace(recordName, domain, "", 1), ".")
} else {
recordInfo.RecordName = "@"
}
if record.TTL == nil {
recordInfo.RecordTTL = "300"
} else {
recordInfo.RecordTTL = fmt.Sprintf("%d", *record.TTL)
}
if record.ResourceRecords != nil {
for _, record := range record.ResourceRecords {
recordInfo.RecordValue = tea.StringValue(record.Value)
dataObj = append(dataObj, recordInfo)
}
} else {
fmt.Println("record value is nil", record)
}
}
}
return dataObj, nil
}

// https://docs.aws.amazon.com/Route53/latest/APIReference/API_ListHostedZones.html
// getDomainList 获取托管区域解析域名列表
func (a *AmazonDNS) getDomainList() (rst []types.HostedZone, err error) {
client := NewAwsDnsClient(a.account.SecretID, a.account.SecretKey)
var Marker *string
for {
output, err := client.ListHostedZones(context.Background(), &route53.ListHostedZonesInput{
Marker: Marker,
})
if err != nil {
return nil, err
}
for _, zone := range output.HostedZones {
rst = append(rst, zone)
}
if output.NextMarker == nil {
break
}
Marker = output.NextMarker
}
return
}

// https://docs.aws.amazon.com/Route53/latest/APIReference/API_ListResourceRecordSets.html
// getRecordList 获取解析记录
func (a *AmazonDNS) getRecordList(domainId string) (rst []types.ResourceRecordSet, err error) {
client := NewAwsDnsClient(a.account.SecretID, a.account.SecretKey)
var startRecordIdentifier *string
var startRecordType types.RRType
var startRecordName *string
for {
output, err := client.ListResourceRecordSets(context.Background(), &route53.ListResourceRecordSetsInput{
HostedZoneId: tea.String(domainId),
StartRecordIdentifier: startRecordIdentifier,
StartRecordType: startRecordType,
StartRecordName: startRecordName,
})
if err != nil {
return nil, err
}
rst = append(rst, output.ResourceRecordSets...)
if output.IsTruncated {
startRecordIdentifier = output.NextRecordIdentifier
startRecordType = output.NextRecordType
startRecordName = output.NextRecordName
} else {
break
}
}
return
}

// https://docs.aws.amazon.com/Route53/latest/APIReference/API_domains_ListDomains.html
// getDomainNameList 获取域名列表
func (a *AmazonDNS) getDomainNameList() (rst []domainTypes.DomainSummary, err error) {
client := NewAwsDomainClient(a.account.SecretID, a.account.SecretKey)
var Marker *string
for {
output, err := client.ListDomains(context.Background(), &route53domains.ListDomainsInput{
Marker: Marker,
})
if err != nil {
return nil, err
}
for _, domain := range output.Domains {
rst = append(rst, domain)
}
if output.NextPageMarker == nil {
break
}
Marker = output.NextPageMarker
}
return
}

// 域名详情接口 https://docs.aws.amazon.com/Route53/latest/APIReference/API_domains_GetDomainDetail.html
// getDomainCreateAndExpiryDate 获取域名创建时间、过期时间, 通过域名详情获取
func (a *AmazonDNS) getDomainCreateAndExpiryDate(domainName string) (d Domain) {
client := NewAwsDomainClient(a.account.SecretID, a.account.SecretKey)
domainDetail, err := client.GetDomainDetail(context.Background(), &route53domains.GetDomainDetailInput{
DomainName: tea.String(domainName),
})
if err != nil {
return
}
d.CreatedDate = domainDetail.CreationDate.String()
d.ExpiryDate = domainDetail.ExpirationDate.String()
if d.ExpiryDate != "" {
d.DaysUntilExpiry = carbon.Now().DiffInDays(carbon.Parse(d.ExpiryDate))
}
return
}
10 changes: 10 additions & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ func init() {
},
}
})
Factory.Register(public.AmazonDnsProvider, func(account map[string]string) DNSProvider {
return &AmazonDNS{
account: public.Account{
CloudProvider: public.AmazonDnsProvider,
CloudName: account["name"],
SecretID: account["secretId"],
SecretKey: account["secretKey"],
},
}
})
Factory.Register(public.DNSLaDnsProvider, func(account map[string]string) DNSProvider {
return &DNSLaDNS{
account: public.Account{
Expand Down
1 change: 1 addition & 0 deletions public/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
GodaddyDnsProvider string = "godaddy"
DNSLaDnsProvider string = "dnsla"
HuaweiDnsProvider string = "huawei"
AmazonDnsProvider string = "amazon"
// Metrics Name
DomainList string = "domain_list"
RecordList string = "record_list"
Expand Down

0 comments on commit af8978e

Please sign in to comment.