Files

311 lines
9.6 KiB
Go

package cloudflare
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"agent-wdd/log"
)
// DNSRecord represents a DNS record in Cloudflare
type DNSRecord struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
Content string `json:"content"`
Priority int `json:"priority,omitempty"`
Proxiable bool `json:"proxiable,omitempty"`
Proxied bool `json:"proxied"`
TTL int `json:"ttl"`
Settings map[string]interface{} `json:"settings,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
Comment string `json:"comment,omitempty"`
Tags []string `json:"tags,omitempty"`
CreatedOn string `json:"created_on,omitempty"`
ModifiedOn string `json:"modified_on,omitempty"`
CommentModifiedOn string `json:"comment_modified_on,omitempty"`
}
// DNSRecordFilter represents filters for listing DNS records
type DNSRecordFilter struct {
Type string
Name string
Content string
Page int
PerPage int
Order string
Direction string
Match string
}
// ListDNSRecords retrieves all DNS records for a zone
//
// Parameters:
// - zoneID: The zone ID
// - filter: Optional filter to apply to the DNS records list
//
// Returns:
// - []DNSRecord: List of DNS records
// - error: Any errors that occurred during the request
func (c *CloudflareClient) ListDNSRecords(zoneID string, filter *DNSRecordFilter) ([]DNSRecord, error) {
log.Debug("Listing DNS records for zone ID: %s with filter: %+v", zoneID, filter)
// Build URL and query parameters
endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseURL, zoneID)
u, err := url.Parse(endpoint)
if err != nil {
log.Error("Failed to parse URL: %v", err)
return nil, fmt.Errorf("failed to parse URL: %w", err)
}
q := u.Query()
if filter != nil {
if filter.Type != "" {
q.Add("type", filter.Type)
}
if filter.Name != "" {
q.Add("name", filter.Name)
}
if filter.Content != "" {
q.Add("content", filter.Content)
}
if filter.Page > 0 {
q.Add("page", strconv.Itoa(filter.Page))
}
if filter.PerPage > 0 {
q.Add("per_page", strconv.Itoa(filter.PerPage))
}
if filter.Order != "" {
q.Add("order", filter.Order)
}
if filter.Direction != "" {
q.Add("direction", filter.Direction)
}
if filter.Match != "" {
q.Add("match", filter.Match)
}
}
u.RawQuery = q.Encode()
// Make request
resp, err := c.doRequest(http.MethodGet, u.String(), nil)
if err != nil {
log.Error("Failed to list DNS records: %v", err)
return nil, fmt.Errorf("failed to list DNS records: %w", err)
}
// Parse response
var records []DNSRecord
result, err := json.Marshal(resp.Result)
if err != nil {
log.Error("Failed to marshal result: %v", err)
return nil, fmt.Errorf("failed to marshal result: %w", err)
}
if err := json.Unmarshal(result, &records); err != nil {
log.Error("Failed to unmarshal DNS records: %v", err)
return nil, fmt.Errorf("failed to unmarshal DNS records: %w", err)
}
// 将域名和ID的映射关系存储到dnsNameToIDMap中
c.dnsNameToIDMap = make(map[string]string, len(records))
for _, record := range records {
c.dnsNameToIDMap[record.Name] = record.ID
}
log.Info("Successfully retrieved %d DNS records for zone ID: %s", len(records), zoneID)
return records, nil
}
// CreateDNSRecord creates a new DNS record in the specified zone
//
// Parameters:
// - zoneID: The zone ID
// - record: The DNS record to create
//
// Returns:
// - *DNSRecord: The created DNS record
// - error: Any errors that occurred during the request
func (c *CloudflareClient) CreateDNSRecord(zoneID string, record DNSRecord) (*DNSRecord, error) {
log.Debug("Creating DNS record in zone ID: %s with data: %+v", zoneID, record)
// Build URL
endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseURL, zoneID)
// Make request
resp, err := c.doRequest(http.MethodPost, endpoint, record)
if err != nil {
log.Error("Failed to create DNS record: %v", err)
return nil, fmt.Errorf("failed to create DNS record: %w", err)
}
// Parse response
var createdRecord DNSRecord
result, err := json.Marshal(resp.Result)
if err != nil {
log.Error("Failed to marshal result: %v", err)
return nil, fmt.Errorf("failed to marshal result: %w", err)
}
if err := json.Unmarshal(result, &createdRecord); err != nil {
log.Error("Failed to unmarshal created DNS record: %v", err)
return nil, fmt.Errorf("failed to unmarshal created DNS record: %w", err)
}
log.Info("Successfully created DNS record: %s (%s) in zone ID: %s", createdRecord.Name, createdRecord.ID, zoneID)
return &createdRecord, nil
}
// GetDNSRecord retrieves a specific DNS record by ID
//
// Parameters:
// - zoneID: The zone ID
// - recordID: The DNS record ID
//
// Returns:
// - *DNSRecord: The DNS record
// - error: Any errors that occurred during the request
func (c *CloudflareClient) GetDNSRecord(zoneID, recordID string) (*DNSRecord, error) {
log.Debug("Getting DNS record ID: %s in zone ID: %s", recordID, zoneID)
// Build URL
endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID)
// Make request
resp, err := c.doRequest(http.MethodGet, endpoint, nil)
if err != nil {
log.Error("Failed to get DNS record: %v", err)
return nil, fmt.Errorf("failed to get DNS record: %w", err)
}
// Parse response
var record DNSRecord
result, err := json.Marshal(resp.Result)
if err != nil {
log.Error("Failed to marshal result: %v", err)
return nil, fmt.Errorf("failed to marshal result: %w", err)
}
if err := json.Unmarshal(result, &record); err != nil {
log.Error("Failed to unmarshal DNS record: %v", err)
return nil, fmt.Errorf("failed to unmarshal DNS record: %w", err)
}
log.Info("Successfully retrieved DNS record: %s (%s) from zone ID: %s", record.Name, record.ID, zoneID)
return &record, nil
}
// UpdateDNSRecord updates an existing DNS record
//
// Parameters:
// - zoneID: The zone ID
// - recordID: The DNS record ID
// - record: The updated DNS record data
//
// Returns:
// - *DNSRecord: The updated DNS record
// - error: Any errors that occurred during the request
func (c *CloudflareClient) UpdateDNSRecord(zoneID, recordID string, record DNSRecord) (*DNSRecord, error) {
log.Debug("Updating DNS record ID: %s in zone ID: %s with data: %+v", recordID, zoneID, record)
// Build URL
endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID)
// Make request
resp, err := c.doRequest(http.MethodPut, endpoint, record)
if err != nil {
log.Error("Failed to update DNS record: %v", err)
return nil, fmt.Errorf("failed to update DNS record: %w", err)
}
// Parse response
var updatedRecord DNSRecord
result, err := json.Marshal(resp.Result)
if err != nil {
log.Error("Failed to marshal result: %v", err)
return nil, fmt.Errorf("failed to marshal result: %w", err)
}
if err := json.Unmarshal(result, &updatedRecord); err != nil {
log.Error("Failed to unmarshal updated DNS record: %v", err)
return nil, fmt.Errorf("failed to unmarshal updated DNS record: %w", err)
}
log.Info("Successfully updated DNS record: %s (%s) in zone ID: %s", updatedRecord.Name, updatedRecord.ID, zoneID)
return &updatedRecord, nil
}
// DeleteDNSRecord deletes a DNS record
//
// Parameters:
// - zoneID: The zone ID
// - recordID: The DNS record ID
//
// Returns:
// - bool: True if the record was deleted successfully
// - error: Any errors that occurred during the request
func (c *CloudflareClient) DeleteDNSRecord(zoneID, recordID string) (bool, error) {
log.Debug("Deleting DNS record ID: %s in zone ID: %s", recordID, zoneID)
// Build URL
endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID)
// Make request
resp, err := c.doRequest(http.MethodDelete, endpoint, nil)
if err != nil {
log.Error("Failed to delete DNS record: %v", err)
return false, fmt.Errorf("failed to delete DNS record: %w", err)
}
// Parse response
result, ok := resp.Result.(map[string]interface{})
if !ok {
log.Error("Unexpected response format for DNS record deletion")
return false, fmt.Errorf("unexpected response format for DNS record deletion")
}
id, ok := result["id"].(string)
if !ok {
log.Error("Failed to extract ID from deletion response")
return false, fmt.Errorf("failed to extract ID from deletion response")
}
log.Info("Successfully deleted DNS record ID: %s from zone ID: %s", id, zoneID)
return true, nil
}
// FindDNSRecord finds a DNS record by name and type
//
// Parameters:
// - zoneID: The zone ID
// - name: The DNS record name
// - recordType: The DNS record type (A, AAAA, CNAME, etc.)
//
// Returns:
// - *DNSRecord: The found DNS record, or nil if not found
// - error: Any errors that occurred during the request
func (c *CloudflareClient) FindDNSRecord(zoneID, name, recordType string) (*DNSRecord, error) {
log.Debug("Finding DNS record with name: %s and type: %s in zone ID: %s", name, recordType, zoneID)
filter := &DNSRecordFilter{
Name: name,
Type: recordType,
}
records, err := c.ListDNSRecords(zoneID, filter)
if err != nil {
return nil, err
}
if len(records) == 0 {
log.Warning("No DNS record found with name: %s and type: %s in zone ID: %s", name, recordType, zoneID)
return nil, nil
}
log.Info("Found DNS record: %s (%s) with type: %s in zone ID: %s", records[0].Name, records[0].ID, records[0].Type, zoneID)
return &records[0], nil
}