dashboard, status API and notifications tell apex domains from hostnames (closes #224)
check / check (push) Successful in 1m15s
check / check (push) Successful in 1m15s
An apex domain's own records are still saved with the hostnames' records, under the domain's name, so the port and TLS checks find its addresses. Notifications about them now start `Domain:`, decided by the configured domains. The dashboard and /api/v1/status, which read only the saved state, take a hostname entry whose name also has a domain entry as that domain's own records: the dashboard shows them in a second table under Domains, the API in the domain's `recordsByNameserver`, and neither lists or counts them as hostnames. The startup notification counts domains and hostnames from the configuration. README says which of a domain's own records are watched and how their changes are notified. Model: opus-5-5
This commit is contained in:
+64
-24
@@ -9,9 +9,12 @@ import (
|
||||
)
|
||||
|
||||
// statusDomainInfo holds status information for a monitored domain.
|
||||
// RecordsByNameserver holds the domain's own records, in the form a
|
||||
// hostname's Nameservers holds the hostname's.
|
||||
type statusDomainInfo struct {
|
||||
Nameservers []string `json:"nameservers"`
|
||||
LastChecked time.Time `json:"lastChecked"`
|
||||
Nameservers []string `json:"nameservers"`
|
||||
RecordsByNameserver map[string]*statusHostnameNSInfo `json:"recordsByNameserver"`
|
||||
LastChecked time.Time `json:"lastChecked"`
|
||||
}
|
||||
|
||||
// statusHostnameNSInfo holds per-nameserver status for a hostname.
|
||||
@@ -100,8 +103,10 @@ func buildStatusResponse(
|
||||
Certificates: make(map[string]*statusCertificateInfo),
|
||||
}
|
||||
|
||||
buildDomains(snap, resp)
|
||||
buildHostnames(snap, resp)
|
||||
hostnames, domainRecords := splitHostnames(snap)
|
||||
|
||||
buildDomains(snap, domainRecords, resp)
|
||||
buildHostnames(hostnames, resp)
|
||||
buildPorts(snap, resp)
|
||||
buildCertificates(snap, resp)
|
||||
buildCounts(resp)
|
||||
@@ -109,8 +114,30 @@ func buildStatusResponse(
|
||||
return resp
|
||||
}
|
||||
|
||||
// splitHostnames returns the records saved in snap.Hostnames in two
|
||||
// maps: the hostnames' and the apex domains' own. The watcher saves a
|
||||
// domain's own records there under the domain's name, which has an
|
||||
// entry in snap.Domains too.
|
||||
func splitHostnames(
|
||||
snap state.Snapshot,
|
||||
) (map[string]*state.HostnameState, map[string]*state.HostnameState) {
|
||||
hostnames := make(map[string]*state.HostnameState)
|
||||
domainRecords := make(map[string]*state.HostnameState)
|
||||
|
||||
for name, hs := range snap.Hostnames {
|
||||
if _, isDomain := snap.Domains[name]; isDomain {
|
||||
domainRecords[name] = hs
|
||||
} else {
|
||||
hostnames[name] = hs
|
||||
}
|
||||
}
|
||||
|
||||
return hostnames, domainRecords
|
||||
}
|
||||
|
||||
func buildDomains(
|
||||
snap state.Snapshot,
|
||||
domainRecords map[string]*state.HostnameState,
|
||||
resp *statusResponse,
|
||||
) {
|
||||
for name, ds := range snap.Domains {
|
||||
@@ -118,41 +145,54 @@ func buildDomains(
|
||||
copy(ns, ds.Nameservers)
|
||||
sort.Strings(ns)
|
||||
|
||||
records := make(map[string]*statusHostnameNSInfo)
|
||||
if hs, ok := domainRecords[name]; ok {
|
||||
records = nameserverInfo(hs)
|
||||
}
|
||||
|
||||
resp.Domains[name] = &statusDomainInfo{
|
||||
Nameservers: ns,
|
||||
LastChecked: ds.LastChecked,
|
||||
Nameservers: ns,
|
||||
RecordsByNameserver: records,
|
||||
LastChecked: ds.LastChecked,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildHostnames(
|
||||
snap state.Snapshot,
|
||||
hostnames map[string]*state.HostnameState,
|
||||
resp *statusResponse,
|
||||
) {
|
||||
for name, hs := range snap.Hostnames {
|
||||
info := &statusHostnameInfo{
|
||||
Nameservers: make(map[string]*statusHostnameNSInfo),
|
||||
for name, hs := range hostnames {
|
||||
resp.Hostnames[name] = &statusHostnameInfo{
|
||||
Nameservers: nameserverInfo(hs),
|
||||
LastChecked: hs.LastChecked,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ns, nsState := range hs.RecordsByNameserver {
|
||||
recs := make(map[string][]string, len(nsState.Records))
|
||||
for rtype, vals := range nsState.Records {
|
||||
copied := make([]string, len(vals))
|
||||
copy(copied, vals)
|
||||
recs[rtype] = copied
|
||||
}
|
||||
// nameserverInfo copies each nameserver's answer saved in hs.
|
||||
func nameserverInfo(
|
||||
hs *state.HostnameState,
|
||||
) map[string]*statusHostnameNSInfo {
|
||||
info := make(map[string]*statusHostnameNSInfo)
|
||||
|
||||
info.Nameservers[ns] = &statusHostnameNSInfo{
|
||||
Records: recs,
|
||||
Status: nsState.Status,
|
||||
Error: nsState.Error,
|
||||
LastChecked: nsState.LastChecked,
|
||||
}
|
||||
for ns, nsState := range hs.RecordsByNameserver {
|
||||
recs := make(map[string][]string, len(nsState.Records))
|
||||
for rtype, vals := range nsState.Records {
|
||||
copied := make([]string, len(vals))
|
||||
copy(copied, vals)
|
||||
recs[rtype] = copied
|
||||
}
|
||||
|
||||
resp.Hostnames[name] = info
|
||||
info[ns] = &statusHostnameNSInfo{
|
||||
Records: recs,
|
||||
Status: nsState.Status,
|
||||
Error: nsState.Error,
|
||||
LastChecked: nsState.LastChecked,
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func buildPorts(
|
||||
|
||||
Reference in New Issue
Block a user