Documentation
¶
Overview ¶
Package dnsstatus reports, for each DNS record a feature needs, whether it is live, still waiting, different or blocked, and what the zone already holds.
Index ¶
- Constants
- func CacheTTL() time.Duration
- func JoinTXT(v string) string
- func Key(wants []Want, parts ...string) string
- func Normalize(typ, v string) string
- type Cache
- type Counts
- type Found
- type Options
- type Record
- type Resolver
- type Status
- type Want
- type WatchCheck
- type WatchConfig
- type WatchEntry
- type WatchEvent
- type WatchNotify
- type WatchSettings
- type WatchState
- type WatchStore
- type Watcher
- func (w *Watcher) Get(domain string) (WatchEntry, bool)
- func (w *Watcher) List() []WatchEntry
- func (w *Watcher) Load(ctx context.Context) error
- func (w *Watcher) Register(ctx context.Context, app, domain string) WatchEntry
- func (w *Watcher) Run(ctx context.Context) error
- func (w *Watcher) Subscribe() (<-chan WatchEvent, func())
- func (w *Watcher) SubscribeWithSnapshot() ([]WatchEntry, <-chan WatchEvent, func())
- func (w *Watcher) Tick(ctx context.Context)
- func (w *Watcher) Unregister(ctx context.Context, domain string)
- type ZoneOptions
- type ZoneSet
Constants ¶
const ( EnvLookupTimeout = "APP_DNS_STATUS_LOOKUP_TIMEOUT" EnvProviderTimeout = "APP_DNS_STATUS_PROVIDER_TIMEOUT" EnvConcurrency = "APP_DNS_STATUS_CONCURRENCY" EnvCacheSeconds = "APP_DNS_STATUS_CACHE_SECONDS" )
Env knobs for public DNS checks and the result cache.
const ( Live = "live" Waiting = "waiting" Different = "different" Conflict = "conflict" Unknown = "unknown" )
Record statuses.
const ( SourceProvider = "provider" SourcePublicDNS = "public_dns" )
Where the found records came from.
const ( WatchEventSnapshot = "snapshot" WatchEventUpdate = "update" WatchEventRemoved = "removed" )
Event kinds a subscriber sees.
Variables ¶
This section is empty.
Functions ¶
func JoinTXT ¶
JoinTXT rejoins a TXT value written as quoted strings (DKIM and SPF are often split into 255 byte chunks) into the single string receivers see.
Types ¶
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache reuses a result for a few seconds and coalesces identical concurrent requests, so a retry burst does one round of lookups. The zero value is ready.
type Counts ¶
type Counts struct {
Live int `json:"live"`
Waiting int `json:"waiting"`
Different int `json:"different"`
Conflict int `json:"conflict"`
Unknown int `json:"unknown"`
Total int `json:"total"`
}
Counts tallies records by status.
type Found ¶
type Found struct {
Type string `json:"type"`
Name string `json:"name"`
Value string `json:"value"`
TTL int `json:"ttl,omitempty"`
Proxied *bool `json:"proxied,omitempty"`
}
Found is one record that already exists at the name.
type Options ¶
Options bounds public DNS checks.
func OptionsFromEnv ¶
func OptionsFromEnv() Options
OptionsFromEnv reads the lookup timeouts and concurrency from env.
type Record ¶
type Record struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Value string `json:"value"`
TTL int `json:"ttl"`
Priority *int `json:"priority,omitempty"`
Status string `json:"status"`
Found []Found `json:"found"`
Reason string `json:"reason,omitempty"`
CheckedAt string `json:"checked_at"`
}
Record is the live status of one wanted record.
type Resolver ¶
type Resolver interface {
LookupTXT(ctx context.Context, name string) ([]string, error)
LookupCNAME(ctx context.Context, name string) (string, error)
LookupMX(ctx context.Context, name string) ([]*net.MX, error)
LookupHost(ctx context.Context, host string) ([]string, error)
LookupSRV(ctx context.Context, service, proto, name string) (string, []*net.SRV, error)
}
Resolver is the slice of net.Resolver a public DNS check needs.
type Status ¶
type Status struct {
ProviderSource string `json:"provider_source"`
CheckedAt string `json:"checked_at"`
Counts Counts `json:"counts"`
Records []Record `json:"records"`
// DelegationWarning means the records come from a provider zone public DNS does not use yet.
DelegationWarning bool `json:"delegation_warning,omitempty"`
DelegationReason string `json:"delegation_reason,omitempty"`
}
Status is the per-record report plus its counts and source.
func FromResolver ¶
FromResolver grades wants against public DNS, a bounded number of lookups at a time.
type Want ¶
type Want struct {
ID string
Type string
Name string
Value string
TTL int
Priority *int
// Reach adds names that must stay unproxied for this record to work (mta-sts).
Reach []string
}
Want is one record a feature needs. Name is absolute without a trailing dot; MX and SRV carry the priority separately from Value.
type WatchCheck ¶
type WatchCheck func(ctx context.Context, domain, app string) (WatchState, error)
WatchCheck reports how far a domain has come. An error keeps the previous state.
type WatchConfig ¶
type WatchConfig struct {
Store WatchStore
Check WatchCheck
Notify WatchNotify
Settings WatchSettings
Now func() time.Time
Logger *slog.Logger
}
WatchConfig wires a Watcher. Now defaults to time.Now; tests pass a fake clock.
type WatchEntry ¶
type WatchEntry struct {
Domain string `json:"domain"`
App string `json:"app"`
State WatchState `json:"state"`
Since time.Time `json:"since"`
LastChecked time.Time `json:"last_checked,omitzero"`
NextCheck time.Time `json:"next_check,omitzero"`
Attempts int `json:"attempts"`
StalledAt time.Time `json:"stalled_at,omitzero"`
Stopped bool `json:"stopped,omitempty"`
NotifiedAt time.Time `json:"notified_at,omitzero"`
}
WatchEntry is one watched domain, also the JSON a client sees.
type WatchEvent ¶
type WatchEvent struct {
Kind string `json:"kind"`
Entry WatchEntry `json:"entry"`
}
WatchEvent is what the stream carries: the entry and why it was sent.
type WatchNotify ¶
type WatchNotify func(ctx context.Context, e WatchEntry) error
WatchNotify tells the user a domain became live. Called once per becoming-live.
type WatchSettings ¶
WatchSettings returns the live poll interval and the time limit before a domain is stalled.
type WatchState ¶
type WatchState string
WatchState is where a watched domain is on its way to serving traffic.
const ( WatchWaitingDNS WatchState = "waiting_dns" WatchPropagating WatchState = "propagating" WatchWaitingCert WatchState = "waiting_certificate" WatchLive WatchState = "live" WatchStalled WatchState = "stalled" )
Watch states, in the order a healthy domain passes through them.
type WatchStore ¶
type WatchStore interface {
ListWatch(ctx context.Context) ([]WatchEntry, error)
SaveWatch(ctx context.Context, e WatchEntry) error
DeleteWatch(ctx context.Context, domain string) error
}
WatchStore persists the watched set so a restart resumes it.
type Watcher ¶
type Watcher struct {
// contains filtered or unexported fields
}
Watcher follows domains that are not answering yet and publishes each change.
func NewWatcher ¶
func NewWatcher(cfg WatchConfig) *Watcher
NewWatcher builds a Watcher; call Load (or Run) to resume persisted domains.
func (*Watcher) Get ¶
func (w *Watcher) Get(domain string) (WatchEntry, bool)
Get returns the entry for domain.
func (*Watcher) List ¶
func (w *Watcher) List() []WatchEntry
List returns every entry ordered by domain.
func (*Watcher) Register ¶
func (w *Watcher) Register(ctx context.Context, app, domain string) WatchEntry
Register starts watching domain for app. A live domain only has its app updated; a stalled or stopped one starts over.
func (*Watcher) Subscribe ¶
func (w *Watcher) Subscribe() (<-chan WatchEvent, func())
Subscribe returns a stream of changes and the function that ends it.
func (*Watcher) SubscribeWithSnapshot ¶
func (w *Watcher) SubscribeWithSnapshot() ([]WatchEntry, <-chan WatchEvent, func())
SubscribeWithSnapshot subscribes and lists in one step so no change falls between them.
type ZoneOptions ¶
type ZoneOptions struct {
// Shadow lists names mail must reach directly; a proxied record there is a conflict.
Shadow map[string]bool
// ProxyAware is true when the provider has a proxy flag, so false is meaningful.
ProxyAware bool
}
ZoneOptions tunes FromZone.