Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions providers/unifi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,26 +245,40 @@ func (c *unifiClient) getSiteID() (string, error) {
return "", fmt.Errorf("site '%s' not found", c.site)
}

// getRecordsNew fetches all DNS policy records using the NEW API.
// dnsPoliciesPageLimit is the number of records to request per page when listing DNS policies.
const dnsPoliciesPageLimit = 200

// getRecordsNew fetches all DNS policy records using the NEW API, paginating as needed.
func (c *unifiClient) getRecordsNew() ([]dnsPolicyRecord, error) {
siteID, err := c.getSiteID()
if err != nil {
return nil, err
}

path := fmt.Sprintf("/integration/v1/sites/%s/dns/policies", siteID)
var allRecords []dnsPolicyRecord
offset := 0
for {
path := fmt.Sprintf("/integration/v1/sites/%s/dns/policies?offset=%d&limit=%d", siteID, offset, dnsPoliciesPageLimit)

respBytes, err := c.do("GET", path, nil)
if err != nil {
return nil, fmt.Errorf("failed to fetch records: %w", err)
}
respBytes, err := c.do("GET", path, nil)
if err != nil {
return nil, fmt.Errorf("failed to fetch records: %w", err)
}

var response dnsPolicyResponse
if err := json.Unmarshal(respBytes, &response); err != nil {
return nil, fmt.Errorf("failed to parse records: %w", err)
var response dnsPolicyResponse
if err := json.Unmarshal(respBytes, &response); err != nil {
return nil, fmt.Errorf("failed to parse records: %w", err)
}

allRecords = append(allRecords, response.Data...)

if len(response.Data) < dnsPoliciesPageLimit {
break
}
offset += dnsPoliciesPageLimit
}

return response.Data, nil
return allRecords, nil
}

// createRecordNew creates a new DNS record using the NEW API.
Expand Down Expand Up @@ -298,8 +312,8 @@ func (c *unifiClient) updateRecordNew(id string, r *dnsPolicyRecord) (*dnsPolicy

path := fmt.Sprintf("/integration/v1/sites/%s/dns/policies/%s", siteID, id)

// Ensure the ID is set in the record
r.ID = id
// The ID is in the URL path; the API rejects it if included in the request body.
r.ID = ""

respBytes, err := c.do("PUT", path, r)
if err != nil {
Expand Down Expand Up @@ -346,7 +360,7 @@ func (c *unifiClient) detectAPIAvailability() {
if _, err := c.getSiteID(); err == nil {
// Site ID fetched successfully, try to get records
siteID := c.siteID
path := fmt.Sprintf("/integration/v1/sites/%s/dns/policies", siteID)
path := fmt.Sprintf("/integration/v1/sites/%s/dns/policies?limit=1", siteID)
if _, err := c.do("GET", path, nil); err == nil {
newAvailable = true
}
Expand Down
23 changes: 11 additions & 12 deletions providers/unifi/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ type dnsPolicyMetadata struct {
// This API is available in UniFi Network 10.1+.
// The record is polymorphic - different fields are used depending on the type.
type dnsPolicyRecord struct {
Type string `json:"type"` // A_RECORD, AAAA_RECORD, CNAME_RECORD, MX_RECORD, TXT_RECORD, SRV_RECORD
ID string `json:"id,omitempty"` // UUID
Enabled bool `json:"enabled"` // Whether the record is enabled
Metadata dnsPolicyMetadata `json:"metadata"` // Metadata (origin)
Domain string `json:"domain"` // FQDN (e.g., "test.example.com")
Type string `json:"type"` // A_RECORD, AAAA_RECORD, CNAME_RECORD, MX_RECORD, TXT_RECORD, SRV_RECORD
ID string `json:"id,omitempty"` // UUID
Enabled bool `json:"enabled"` // Whether the record is enabled
Metadata *dnsPolicyMetadata `json:"metadata,omitempty"` // Metadata (origin, read-only in API responses)
Domain string `json:"domain"` // FQDN (e.g., "test.example.com")

// TTL (optional, 0 = default)
TTLSeconds int `json:"ttlSeconds,omitempty"`
// TTL in seconds (required by the API, always sent)
TTLSeconds int `json:"ttlSeconds"`

// Type-specific fields
IPv4Address string `json:"ipv4Address,omitempty"` // A record
Expand Down Expand Up @@ -289,14 +289,13 @@ func recordToNew(rc *models.RecordConfig) (*dnsPolicyRecord, error) {
r := &dnsPolicyRecord{
Enabled: true,
Domain: rc.NameFQDN,
Metadata: dnsPolicyMetadata{
Origin: "USER_DEFINED",
},
}

// Set TTL if non-default
if rc.TTL > 0 && rc.TTL != 300 {
// Always send TTL; the API requires ttlSeconds to be non-null.
if rc.TTL > 0 {
r.TTLSeconds = int(rc.TTL)
} else {
r.TTLSeconds = 300
}

switch rc.Type {
Expand Down