Documentation
¶
Overview ¶
internal/cloudflare/interfaces.go
Index ¶
- Constants
- Variables
- func AffixName(fqdn, recordType string, cfg AffixConfig) string
- func DecryptPayload(input string, keys [][]byte) (string, error)
- func EncodeRegistryPayload(p RegistryPayload) string
- func EncryptPayload(plaintext string, key []byte) (string, error)
- func IsBadRequest(err error) bool
- func IsNotFound(err error) bool
- func IsPermissionDenied(err error) bool
- func IsPlanTierRequired(err error) bool
- func IsTunnelHasActiveConnections(err error) bool
- func NewCloudflareClient(apiToken string) *cfgo.Client
- type AffixConfig
- type BotManagementConfig
- type ClientFactory
- type Credentials
- type DNSClient
- type DNSRecord
- type DNSRecordParams
- type RegistryPayload
- type RuleLogging
- type Ruleset
- type RulesetClient
- type RulesetParams
- type RulesetRule
- type Tunnel
- type TunnelClient
- type TunnelParams
- type Zone
- type ZoneClient
- type ZoneLifecycleClient
- type ZoneLifecycleEditParams
- type ZoneLifecycleParams
- type ZoneSetting
Constants ¶
const ( SecretKeyAPIToken = "apiToken" SecretKeyAccountID = "accountID" )
Secret data keys where Cloudflare credentials are expected.
Variables ¶
var ErrPhaseEntrypointNotFound = errors.New("phase entrypoint not found")
ErrPhaseEntrypointNotFound is returned by GetPhaseEntrypoint when no entrypoint ruleset has been created yet for the requested phase. The caller should treat this as "start from scratch" and proceed to UpsertPhaseEntrypoint.
var ErrRegistryMalformed = errors.New("txt registry: malformed payload")
ErrRegistryMalformed is returned when a TXT payload cannot be parsed as an external-dns registry entry.
This error deliberately covers BOTH cases:
- The TXT is not an external-dns registry record at all (e.g. an SPF record, a user-managed TXT, or any other non-registry payload whose heritage key is missing or not "external-dns").
- The TXT looks like a registry record but is structurally invalid (e.g. missing owner, malformed resource tuple, missing '=' separator).
Callers MUST NOT try to distinguish these two cases: both mean "do not treat this TXT as ownership metadata." Wrapping them under a single sentinel keeps adoption logic simple — any error from DecodeRegistryPayload means "ignore this record for registry purposes."
var ErrSecretNotLabeled = errors.New(
"secret exists but is not labeled cloudflare.io/managed=true")
ErrSecretNotLabeled is returned by GetCredentials when the referenced Secret exists in the API server but is missing the cloudflare.io/managed=true label, so the operator's cache filter has excluded it. Distinct from a genuine NotFound — see GetCredentials.
var ErrZoneNotFound = errors.New("zone not found")
ErrZoneNotFound is returned by GetZone when the Cloudflare API responds with 404. Callers can distinguish not-found from transient errors with errors.Is.
Functions ¶
func AffixName ¶ added in v0.6.0
func AffixName(fqdn, recordType string, cfg AffixConfig) string
AffixName returns the companion-TXT record name for a managed record at fqdn with the given record type. Matches external-dns's default affix scheme.
func DecryptPayload ¶ added in v0.6.0
DecryptPayload attempts to decrypt a base64-encoded AES-256-CBC ciphertext using any key in keys (tried in order). If the input does not parse as base64 or does not look encrypted at all, it is returned verbatim (plaintext passthrough). If the input is encrypted but no key decrypts it cleanly, returns an error.
"Looks encrypted" is determined by base64 decoding successfully to at least two AES blocks (IV + one block of ciphertext).
func EncodeRegistryPayload ¶ added in v0.6.0
func EncodeRegistryPayload(p RegistryPayload) string
EncodeRegistryPayload produces the canonical quoted wire form of a RegistryPayload.
func EncryptPayload ¶ added in v0.6.0
EncryptPayload produces a base64-encoded AES-256-CBC ciphertext of plaintext using key. The output format is external-dns-compatible:
base64( IV[16] || PKCS#7-padded-ciphertext )
key MUST be 32 bytes (AES-256).
func IsBadRequest ¶ added in v0.12.0
IsBadRequest reports whether err originated from a Cloudflare API 400 response. The user must edit the spec; the operator cannot fix this.
func IsNotFound ¶ added in v0.12.0
IsNotFound reports whether err originated from a Cloudflare API 404 response. Wrapped errors are unwrapped via errors.As.
func IsPermissionDenied ¶ added in v0.6.1
IsPermissionDenied reports whether err originated from a Cloudflare API 403 response. The most common cause is a missing token scope (e.g., Zone:Bot Management Write) or a plan that does not permit the requested setting (e.g., bot_management on a Free zone). Wrapped errors are unwrapped via errors.As.
func IsPlanTierRequired ¶ added in v0.12.0
IsPlanTierRequired reports whether err is a Cloudflare 403 carrying an error code in planTierErrorCodes. Distinguishes plan-restricted features (e.g. BotManagement on Free) from token-permission denials.
func IsTunnelHasActiveConnections ¶ added in v0.17.0
IsTunnelHasActiveConnections reports whether err is a Cloudflare 400 carrying error code 1022. Cloudflare returns this when DeleteTunnel is called while cloudflared replicas are still connected. The operator handles this by scaling its managed connector Deployment to zero before calling DeleteTunnel, but a transient drain-tail can still surface this error briefly after pods exit; in that case the caller should requeue with backoff.
func NewCloudflareClient ¶
NewCloudflareClient creates a new Cloudflare API client from an API token.
Types ¶
type AffixConfig ¶ added in v0.6.0
AffixConfig controls how the companion TXT's record name is derived from the managed record's FQDN. Defaults (all empty strings) yield external-dns's default affix scheme.
type BotManagementConfig ¶
BotManagementConfig represents bot management settings. Pointer fields allow distinguishing between "unset" and "set to false".
type ClientFactory ¶
type ClientFactory struct {
// contains filtered or unexported fields
}
ClientFactory creates Cloudflare API clients from Kubernetes Secrets.
k8sClient is the cached client used for steady-state Secret reads. apiReader is the manager's uncached API reader, used only to disambiguate the cache-miss path (label-filtered vs. truly missing). In tests where the cache and API server are not distinguished, the same reader may be passed for both fields.
func NewClientFactory ¶
func NewClientFactory(k8sClient client.Client, apiReader client.Reader) *ClientFactory
NewClientFactory creates a new ClientFactory. apiReader must be the manager's non-caching API reader (mgr.GetAPIReader()) so the disambiguation path bypasses the (label-filtered) cache.
func (*ClientFactory) GetAPIToken ¶
func (f *ClientFactory) GetAPIToken(ctx context.Context, secretName, namespace string) (string, error)
GetAPIToken reads a Cloudflare API token from a Kubernetes Secret.
func (*ClientFactory) GetCredentials ¶ added in v0.5.0
func (f *ClientFactory) GetCredentials(ctx context.Context, secretName, namespace string) (Credentials, error)
GetCredentials reads the Cloudflare API token (required) and Account ID (optional, empty string if not set) from a single Kubernetes Secret.
On cache miss (k8sClient returns IsNotFound), GetCredentials does a single uncached read via apiReader to disambiguate:
- apiReader also returns IsNotFound → the original cache error is returned (downstream surfaces ReasonSecretNotFound as today).
- apiReader returns the Secret → the Secret exists in the API server but the cache filter has excluded it; ErrSecretNotLabeled is returned so reconcilers can surface the actionable ReasonSecretNotLabeled message.
- apiReader returns any other error → that error is returned (rare, e.g. transient API server unavailability on the slow path).
The fallback runs only on the cache-miss path. Steady-state credential reads remain fully cached.
type Credentials ¶ added in v0.5.0
Credentials holds the Cloudflare API token and, optionally, the Account ID read from a single Kubernetes Secret.
type DNSClient ¶
type DNSClient interface {
GetRecord(ctx context.Context, zoneID, recordID string) (*DNSRecord, error)
ListRecordsByNameAndType(ctx context.Context, zoneID, name, recordType string) ([]DNSRecord, error)
CreateRecord(ctx context.Context, zoneID string, params DNSRecordParams) (*DNSRecord, error)
UpdateRecord(ctx context.Context, zoneID, recordID string, params DNSRecordParams) (*DNSRecord, error)
DeleteRecord(ctx context.Context, zoneID, recordID string) error
}
DNSClient manages Cloudflare DNS records.
func NewDNSClientFromCF ¶
NewDNSClientFromCF creates a DNSClient from a cloudflare-go Client.
type DNSRecord ¶
type DNSRecord struct {
ID string
Name string
Type string
Content string
Proxied bool
TTL int
Data map[string]any
}
DNSRecord represents a Cloudflare DNS record.
type DNSRecordParams ¶
type DNSRecordParams struct {
Name string
Type string
Content string
Proxied *bool
TTL int
Priority *int
Data map[string]any
}
DNSRecordParams are parameters for creating/updating a DNS record.
type RegistryPayload ¶ added in v0.6.0
type RegistryPayload struct {
Owner string
SourceKind string
SourceNamespace string
SourceName string
}
RegistryPayload is the decoded external-dns-compatible TXT registry entry.
Wire format:
"heritage=external-dns,external-dns/owner=<owner>,external-dns/resource=<kind>/<ns>/<name>"
SourceKind / SourceNamespace / SourceName may be empty for legacy external-dns registry entries that only carry owner information. Callers should treat missing resource information as "adoptable but unlinked".
func DecodeRegistryPayload ¶ added in v0.6.0
func DecodeRegistryPayload(raw string) (RegistryPayload, error)
DecodeRegistryPayload parses the wire form produced by EncodeRegistryPayload. Accepts both quoted and unquoted forms (Cloudflare's DNS API sometimes strips surrounding quotes on read).
type RuleLogging ¶ added in v0.7.0
type RuleLogging struct {
Enabled *bool
}
RuleLogging configures per-rule logging behavior. Pointer Enabled so callers can distinguish "unset" (nil) from "set to false".
type Ruleset ¶
type Ruleset struct {
ID string
Name string
Description string
Phase string
Rules []RulesetRule
}
Ruleset represents a Cloudflare Ruleset.
type RulesetClient ¶
type RulesetClient interface {
// GetPhaseEntrypoint returns the zone's entrypoint ruleset for the given
// phase. Returns ErrPhaseEntrypointNotFound when the entrypoint has not
// been created yet (no Update has ever been made for that phase on this
// zone). Any other error indicates an API / transport failure.
GetPhaseEntrypoint(ctx context.Context, zoneID, phase string) (*Ruleset, error)
// UpsertPhaseEntrypoint writes the given rules to the zone's entrypoint
// ruleset for the given phase. Creates the entrypoint if it does not
// already exist, otherwise replaces its rule set.
UpsertPhaseEntrypoint(ctx context.Context, zoneID, phase string, params RulesetParams) (*Ruleset, error)
}
RulesetClient manages a zone's phase-entrypoint rulesets.
Cloudflare has two ruleset kinds: "zone" (the phase entrypoint — one per phase per zone, what the dashboard surfaces as Security rules / Custom rules / Rate limiting rules / etc.) and "custom" (standalone rulesets, a Business+ feature). The operator manages the phase entrypoint so it works on all plans.
func NewRulesetClientFromCF ¶
func NewRulesetClientFromCF(cf *cfgo.Client) RulesetClient
NewRulesetClientFromCF creates a RulesetClient from a cloudflare-go Client.
type RulesetParams ¶
type RulesetParams struct {
Name string
Description string
Phase string
Rules []RulesetRule
}
RulesetParams are parameters for creating/updating a ruleset.
type RulesetRule ¶
type RulesetRule struct {
ID string
Action string
Expression string
Description string
Enabled bool
ActionParameters map[string]any
Logging *RuleLogging
}
RulesetRule is a single rule in a ruleset.
type TunnelClient ¶
type TunnelClient interface {
GetTunnel(ctx context.Context, accountID, tunnelID string) (*Tunnel, error)
ListTunnelsByName(ctx context.Context, accountID, name string) ([]Tunnel, error)
CreateTunnel(ctx context.Context, accountID string, params TunnelParams) (*Tunnel, error)
DeleteTunnel(ctx context.Context, accountID, tunnelID string) error
}
TunnelClient manages Cloudflare Tunnels.
func NewTunnelClientFromCF ¶
func NewTunnelClientFromCF(cf *cfgo.Client) TunnelClient
NewTunnelClientFromCF creates a TunnelClient from a cloudflare-go Client.
type TunnelParams ¶
TunnelParams are parameters for creating a tunnel.
type Zone ¶
type Zone struct {
ID string
Name string
Status string // initializing, pending, active, moved
Type string // full, partial, secondary
Paused bool
NameServers []string
OriginalNameServers []string
OriginalRegistrar string
VerificationKey string
ActivatedOn *time.Time
}
Zone represents a Cloudflare Zone (lifecycle information).
type ZoneClient ¶
type ZoneClient interface {
GetSettings(ctx context.Context, zoneID string) ([]ZoneSetting, error)
UpdateSetting(ctx context.Context, zoneID, settingID string, value any) error
GetBotManagement(ctx context.Context, zoneID string) (*BotManagementConfig, error)
UpdateBotManagement(ctx context.Context, zoneID string, config BotManagementConfig) error
}
ZoneClient manages Cloudflare Zone settings and bot management.
func NewZoneClientFromCF ¶
func NewZoneClientFromCF(cf *cfgo.Client) ZoneClient
NewZoneClientFromCF creates a ZoneClient from a cloudflare-go Client.
type ZoneLifecycleClient ¶
type ZoneLifecycleClient interface {
CreateZone(ctx context.Context, accountID string, params ZoneLifecycleParams) (*Zone, error)
GetZone(ctx context.Context, zoneID string) (*Zone, error)
ListZonesByName(ctx context.Context, accountID, name string) ([]Zone, error)
EditZone(ctx context.Context, zoneID string, params ZoneLifecycleEditParams) (*Zone, error)
DeleteZone(ctx context.Context, zoneID string) error
TriggerActivationCheck(ctx context.Context, zoneID string) error
}
ZoneLifecycleClient manages Cloudflare Zone lifecycle (create/get/list/edit/delete).
func NewZoneLifecycleClientFromCF ¶
func NewZoneLifecycleClientFromCF(cf *cfgo.Client) ZoneLifecycleClient
NewZoneLifecycleClientFromCF creates a ZoneLifecycleClient from a cloudflare-go Client.
type ZoneLifecycleEditParams ¶
type ZoneLifecycleEditParams struct {
Paused *bool
}
ZoneLifecycleEditParams are parameters for editing a zone.
type ZoneLifecycleParams ¶
ZoneLifecycleParams are parameters for creating a zone.
type ZoneSetting ¶
ZoneSetting is a key-value pair for a zone setting.