Added:
- Server statistics: named's memory and CPU (from /proc), cache size,
sockets and client counts against their limits (statistics channel,
rndc status), host memory and load, and free disk space. Memory and
CPU are kept over time as gauges (sum and sample count, averaged in
timelines). Statistics page Server section, jarl stats server,
GET /stats/server.
- jarl record add|set|delete|disable|enable --view a,b | all: the same
change in each view, applied as one changeset.
- Blocking can be paused until resumed (jarl block pause indefinitely,
"Until I resume", {"indefinitely": true}).
Changed:
- List options (allow-transfer, forwarders, ...) get their braces added
when given without them.
- The dashboard lists named-checkconf's warnings about the running
configuration; the CLI prints them after an apply.
- Stats page: tile and card rows fill their width, and the queries and
failed answers charts share margins so their time axes line up.
- Dashboard: options have their own tile.
- 24-hour times in the web UI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
2.3 KiB
Go
78 lines
2.3 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"jarl/internal/model"
|
|
"jarl/internal/render"
|
|
"jarl/internal/validate"
|
|
)
|
|
|
|
// namedCheckTTL is how long the result of checking named's running
|
|
// configuration is kept when nothing changed.
|
|
const namedCheckTTL = 10 * time.Minute
|
|
|
|
// namedCheck caches the warnings of named-checkconf on the configuration
|
|
// named runs, keyed by what it depends on.
|
|
type namedCheck struct {
|
|
mu sync.Mutex
|
|
key string
|
|
at time.Time
|
|
problems []validate.Problem
|
|
}
|
|
|
|
// namedProblems runs named-checkconf on the configuration named runs
|
|
// (without loading zones, which is quick) and returns what it reports as
|
|
// problems. An apply shows these too, but they are named's own checks,
|
|
// which Jarl doesn't repeat ("both recursion no and allow-recursion
|
|
// active"): the dashboard lists them with Jarl's so they don't go unseen
|
|
// after the apply. The result is reused while the deployed files and
|
|
// named's main file are unchanged.
|
|
func (e *Engine) namedProblems(ctx context.Context, st *model.State, deployed map[string]*model.DeployedFile) []validate.Problem {
|
|
if e.tools == nil || e.cfg.SkipCheck || e.cfg.MainConfig == "" || len(deployed) == 0 {
|
|
return nil
|
|
}
|
|
key := ""
|
|
if fi, err := os.Stat(e.cfg.MainConfig); err == nil {
|
|
key = fi.ModTime().String()
|
|
}
|
|
if f := deployed[e.cfg.Paths.MainConfig()]; f != nil {
|
|
key += "|" + f.SHA256
|
|
}
|
|
c := &e.namedCheck
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
if c.key == key && e.Now().Sub(c.at) < namedCheckTTL {
|
|
return c.problems
|
|
}
|
|
res, err := e.tools.CheckConfig(ctx, e.cfg.MainConfig, false)
|
|
if err != nil {
|
|
return nil // named-checkconf couldn't run; an apply reports that
|
|
}
|
|
out := render.Render(st, e.cfg.Paths, e.cfg.Extras)
|
|
var ps []validate.Problem
|
|
for _, m := range res.Messages {
|
|
p := validate.Problem{Severity: validate.Warning, Code: "named_warning", View: m.View, Zone: m.Zone}
|
|
if m.Error {
|
|
p.Severity, p.Code = validate.Error, "named_error"
|
|
}
|
|
where := ""
|
|
if m.File != "" {
|
|
where = fmt.Sprintf(" (%s:%d)", m.File, m.Line)
|
|
}
|
|
if span, ok := out.Lookup(m.File, m.Line); ok {
|
|
p.ObjectType, p.ObjectID = span.ObjectType, span.ObjectID
|
|
where = " (" + span.Label + ", " + where[2:]
|
|
}
|
|
p.Message = "named-checkconf: " + strings.TrimSpace(m.Text) + where
|
|
ps = append(ps, p)
|
|
}
|
|
c.key, c.at, c.problems = key, e.Now(), ps
|
|
return ps
|
|
}
|