cloudns

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2026 License: MIT Imports: 14 Imported by: 5

README

ClouDNS for libdns

Go Reference

This package implements the libdns interfaces for the ClouDNS HTTP API, allowing you to manage DNS records in ClouDNS-hosted zones:

  • libdns.RecordGetter — list records
  • libdns.RecordAppender — create records
  • libdns.RecordSetter — create or update records in place
  • libdns.RecordDeleter — delete records
  • libdns.ZoneLister — list zones

Installation

go get github.com/libdns/cloudns

Authentication

The provider authenticates with the ClouDNS API using one of the three credential types ClouDNS offers (managed in the ClouDNS control panel under API & Resellers), plus the API password:

Field ClouDNS parameter Description
AuthId auth-id API user ID
SubAuthId sub-auth-id API sub-user ID
SubAuthUser sub-auth-user API sub-user name
AuthPassword auth-password API password (always required)

Set exactly one of AuthId, SubAuthId, or SubAuthUser. If more than one is set, they take precedence in that order.

Upgrading from v1.x — breaking change: the precedence flipped. v1.x releases preferred SubAuthId over AuthId when both were set; this version prefers AuthId. If your configuration sets more than one credential field, remove the ones you do not intend to authenticate with.

Note: ClouDNS restricts API access per API user (allowed IPs, allowed zones). Make sure the API user you use is permitted to manage the zone from the machine running your program.

Usage

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/libdns/cloudns"
	"github.com/libdns/libdns"
)

func main() {
	provider := &cloudns.Provider{
		AuthId:       "your_auth_id",
		AuthPassword: "your_auth_password",
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	zone := "example.com." // zones are fully qualified, with a trailing dot

	// List records.
	records, err := provider.GetRecords(ctx, zone)
	if err != nil {
		panic(err)
	}
	fmt.Printf("records: %+v\n", records)

	// Create a record. Names are relative to the zone; "@" is the apex.
	created, err := provider.AppendRecords(ctx, zone, []libdns.Record{
		libdns.TXT{
			Name: "_acme-challenge",
			TTL:  60 * time.Second,
			Text: "validation-token",
		},
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("created: %+v\n", created)

	// Update the record in place (SetRecords replaces the whole RRset).
	_, err = provider.SetRecords(ctx, zone, []libdns.Record{
		libdns.TXT{
			Name: "_acme-challenge",
			TTL:  60 * time.Second,
			Text: "new-validation-token",
		},
	})
	if err != nil {
		panic(err)
	}

	// Clean up. Leaving TTL/data zero-valued deletes regardless of their value.
	_, err = provider.DeleteRecords(ctx, zone, []libdns.Record{
		libdns.RR{Name: "_acme-challenge", Type: "TXT"},
	})
	if err != nil {
		panic(err)
	}
}

Configuration reference

All fields other than the credentials are optional:

Field Default Description
OperationRetries 5 Max attempts per API call (transient failures only)
InitialBackoff 1s Delay before the first retry; doubles after each attempt
MaxBackoff 30s Upper bound for the retry delay
BaseURL https://api.cloudns.net/dns/ API endpoint override (mostly for testing)
HTTPClient 30s-timeout client Custom *http.Client for API requests

Only transient failures are retried: network errors, HTTP 429 (the ClouDNS API is rate-limited to 20 requests/second per IP), and HTTP 5xx. Logical API failures (bad credentials, invalid parameters) fail immediately.

Behavior notes

  • Record types. A, AAAA, CNAME, MX, NS, SRV, TXT, CAA, HTTPS, and SVCB records are fully modeled with the corresponding libdns types. Other types supported by ClouDNS (e.g. ALIAS, PTR, SSHFP, NAPTR) are passed through as generic libdns.RR values whose Data carries the primary record value.
  • TTLs. ClouDNS only accepts a fixed set of TTL values (60 to 2592000 seconds). TTLs are rounded up to the nearest accepted value; a zero TTL becomes 60 seconds.
  • Apex records. Use "@" as the record name for the zone apex, per the libdns convention. The provider translates it to the empty host ClouDNS uses on the wire.
  • Long TXT records. The ClouDNS API returns TXT values longer than 255 bytes as multiple quoted chunks; the provider reassembles them into a single string.
  • Atomicity. ClouDNS has no batch or transactional API. SetRecords and the other mutating methods apply changes one record at a time and are not atomic; on error, the zone may be left partially modified. SetRecords attempts every planned operation and returns all errors joined together.
  • Concurrency. A Provider is safe for concurrent use: SetRecords and DeleteRecords serialize their read-modify-write cycles per Provider instance, so simultaneous calls see each other's changes. Configuration fields must not be modified after the first method call.

Testing

The unit and integration tests run against an in-memory mock of the ClouDNS API and require no credentials:

go test ./...

To additionally exercise the live ClouDNS API, provide credentials and a dedicated test zone via the environment; the live test manages only records named libdns-test* within that zone:

export CLOUDNS_AUTH_ID="your_auth_id"           # or CLOUDNS_SUB_AUTH_ID / CLOUDNS_SUB_AUTH_USER
export CLOUDNS_AUTH_PASSWORD="your_auth_password"
export CLOUDNS_TEST_ZONE="example.com"
go test -run TestLiveAPI ./...

License

This project is licensed under the MIT License. See the LICENSE file for details.

Documentation

Overview

Package cloudns implements the libdns interfaces for the ClouDNS HTTP API, allowing DNS records in ClouDNS-hosted zones to be listed, created, updated, and deleted.

The provider authenticates with the ClouDNS API using an API user ID (auth-id), an API sub-user ID (sub-auth-id), or an API sub-user name (sub-auth-user), together with the API password. API users are managed in the ClouDNS control panel under "API & Resellers".

Index

Constants

View Source
const (
	// DefaultOperationRetries is the default maximum number of attempts
	// for each API call (the first try plus retries).
	DefaultOperationRetries = 5

	// DefaultInitialBackoff is the default delay before the first retry;
	// it doubles after every failed attempt.
	DefaultInitialBackoff = 1 * time.Second

	// DefaultMaxBackoff is the default upper bound for the retry delay.
	DefaultMaxBackoff = 30 * time.Second
)

Default retry configuration, applied when the corresponding Provider fields are left at their zero values.

Variables

This section is empty.

Functions

This section is empty.

Types

type Provider

type Provider struct {
	// AuthId is the ClouDNS API user ID ("auth-id").
	AuthId string `json:"auth_id,omitempty"`

	// SubAuthId is the ClouDNS API sub-user ID ("sub-auth-id").
	// It is consulted only if AuthId is empty.
	SubAuthId string `json:"sub_auth_id,omitempty"`

	// SubAuthUser is the ClouDNS API sub-user name ("sub-auth-user").
	// It is consulted only if AuthId and SubAuthId are empty.
	SubAuthUser string `json:"sub_auth_user,omitempty"`

	// AuthPassword is the password of the API user or sub-user.
	AuthPassword string `json:"auth_password"`

	// OperationRetries is the maximum number of attempts for each API
	// call. Only transient failures (network errors, HTTP 429, and
	// HTTP 5xx responses) are retried. Defaults to DefaultOperationRetries.
	OperationRetries int `json:"operation_retries,omitempty"`

	// InitialBackoff is the delay before the first retry; it doubles
	// after every failed attempt. Defaults to DefaultInitialBackoff.
	InitialBackoff time.Duration `json:"initial_backoff,omitempty"`

	// MaxBackoff caps the exponentially growing retry delay.
	// Defaults to DefaultMaxBackoff.
	MaxBackoff time.Duration `json:"max_backoff,omitempty"`

	// BaseURL overrides the ClouDNS API endpoint. Defaults to
	// "https://api.cloudns.net/dns/". Mainly useful for testing.
	BaseURL string `json:"-"`

	// HTTPClient overrides the HTTP client used for API requests.
	// Defaults to a client with a 30-second timeout.
	HTTPClient *http.Client `json:"-"`
	// contains filtered or unexported fields
}

Provider facilitates DNS record manipulation with ClouDNS.

Exactly one of AuthId, SubAuthId, or SubAuthUser must be set, along with AuthPassword. All other fields are optional.

The zero value of each optional field means "use the default". A Provider must not be copied after first use, and its configuration fields must not be modified after the first method call. Its methods are safe for concurrent use: SetRecords and DeleteRecords serialize their read-modify-write cycles per Provider instance, so simultaneous calls see each other's changes. (Calls made through separate Provider instances or processes are not synchronized.)

func (*Provider) AppendRecords

func (p *Provider) AppendRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error)

AppendRecords adds records to the zone and returns the records that were created. It never modifies or deletes existing records.

The operation is not atomic: records are created one at a time, in order. If a record fails to be created, the records created so far are returned together with the error.

func (*Provider) DeleteRecords

func (p *Provider) DeleteRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error)

DeleteRecords deletes the records from the zone that exactly match the input records, and returns the records that were deleted. Input records that do not exist in the zone are silently ignored.

As allowed by the libdns specification, the type, TTL, and data of an input record may be left as their zero values to match any value of that field; the name must always be specified ("@" for the zone apex).

The operation is not atomic: records are deleted one at a time, and if a deletion fails, the records deleted so far are returned together with the error.

func (*Provider) GetRecords

func (p *Provider) GetRecords(ctx context.Context, zone string) ([]libdns.Record, error)

GetRecords lists all the records in the zone.

Records of types not modeled by the libdns package (for example WR or NAPTR) are returned as generic libdns.RR values whose Data holds the primary "record" field reported by ClouDNS.

func (*Provider) ListZones added in v1.2.0

func (p *Provider) ListZones(ctx context.Context) ([]libdns.Zone, error)

ListZones returns all DNS zones managed by this account, using pagination as required by the ClouDNS API.

func (*Provider) SetRecords

func (p *Provider) SetRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error)

SetRecords updates the zone so that the records provided in the input are the only records of their (name, type) RRset. RRsets not named in the input are left untouched. It returns the records that are now present in the affected RRsets.

ClouDNS does not offer batch or atomic operations, so SetRecords is NOT atomic: if an error occurs partway, the zone may be left with some changes applied and others not. No rollback is attempted. All planned operations are attempted even if one of them fails, and all errors are joined and returned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL