Documentation
¶
Overview ¶
Package trackfile reads and monitors the files that `track_file` names, and turns their contents into the status a tracking object sees.
It backs two things that look unrelated in the configuration: FILE_CHECK on a real server (check_file.c) and `track_file` on a VRRP instance (vrrp_track.c). Both are the same mechanism — an external agent writes a number to a file, and keepalived reacts — and both go through keepalived/trackers/track_file.c.
The value is read on startup and then again whenever inotify says the file changed. There is no polling and no timeout: a file that stops being updated keeps its last value indefinitely, which is worth knowing when the agent writing it dies.
Index ¶
Constants ¶
const ( // WeightMax is IPVS_WEIGHT_MAX / IPVS_WEIGHT_LIMIT. WeightMax = math.MaxInt32 // WeightFault is IPVS_WEIGHT_FAULT, the sentinel meaning "in fault // state" rather than "weight -2147483648". It is also what // `weight_range` clamps to at the bottom, so a large enough negative // product becomes a fault by arithmetic rather than by intent. WeightFault = math.MinInt32 )
Weight limits (keepalived/include/ip_vs.h:23-25).
const ReadLimit = 127
ReadLimit is the number of bytes read from a tracked file (process_track_file, track_file.c:810 — `char buf[128]` read with `sizeof(buf) - 1`).
Anything past it is not read at all, so a file whose number starts after 127 bytes of whitespace parses as zero rather than as an error.
Variables ¶
var ErrOutOfRange = errors.New("trackfile: value out of range")
ErrOutOfRange is returned for a value outside what a tracked file may hold.
Functions ¶
func ParseValue ¶
ParseValue decodes the contents of a tracked file (process_track_file, track_file.c:806-841).
The rules come from C's `strtol(buf, NULL, 0)` plus the range test that follows it, and three of them are not obvious:
- Base 0. "0x10" is 16 and "010" is 8. A monitoring agent writing zero-padded decimal is writing octal.
- Trailing garbage is ignored. "1abc" is 1, and "abc" is 0 — strtol converts nothing, returns 0, and C only inspects errno for range errors. A file containing an error message therefore reads as zero, which for an unweighted tracker is the *healthy* value.
- The upper bound is INT32_MAX + 1, not INT32_MAX (track_file.c:826). So 2147483648 is accepted and 2147483649 is not. The value is later stored in an int32 field, so the one accepted out-of-range value wraps.
A rejected value leaves the previous status in place; C returns early without updating anything.
func Status ¶
Status converts a tracked file's value into the status a tracking object sees (update_track_file_status, track_file.c:788-793).
weight 0: !value != (multiplier == 1) ? INT_MIN : 0 otherwise: clamp(value × weight × multiplier)
The unweighted case is worth spelling out, because the double negation hides what it does. With reverse false (multiplier +1) a *zero* value is healthy and anything else is a fault. With reverse true the sense is inverted: a non-zero value is healthy. So the file's natural reading — "0 means OK" — only holds for an unweighted, non-reversed tracker, and the same file drives a weighted tracker in the opposite direction, where 0 contributes nothing and a positive value adds weight.
Types ¶
type Event ¶
type Event struct {
// Name is the track_file name from the configuration.
Name string
// Value is the new value. A deleted file reports zero.
Value int64
// Deleted reports that the file went away rather than being rewritten.
Deleted bool
}
Event reports a tracked file's new value.
type File ¶
type File struct {
// Name is the track_file name.
Name string
// Path is the file to watch.
Path string
// contains filtered or unexported fields
}
File is one file being tracked.
type Monitor ¶
type Monitor struct {
// contains filtered or unexported fields
}
Monitor watches a set of tracked files and reports value changes.
It reports only *changes*: C's update_track_file_status returns immediately when the new status equals the last one (track_file.c:781), so a writer rewriting the same value produces no work. Suppressing it here rather than in the consumer keeps that guarantee in one place.
func (*Monitor) Add ¶
Add registers a file and returns its current value.
The initial read is what C does at startup with `process_track_file(tfile, true)` — the value is recorded but no transition is reported, because there is no previous state to have moved from.
A file that does not exist is not an error. It reads as zero, and the watch on its directory means creating it later is noticed. This matters: it is the normal way to configure a tracker whose agent has not started yet.
func (*Monitor) Fd ¶
Fd exposes the inotify descriptor so a caller can wait on it with its own event loop rather than blocking in Read.