trackfile

package
v0.0.0-...-efbc44a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: GPL-2.0 Imports: 10 Imported by: 0

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

View Source
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).

View Source
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

View Source
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

func ParseValue(b []byte) (int64, error)

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

func Status(value int64, weight int, reverse bool) int

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 NewMonitor

func NewMonitor() (*Monitor, error)

NewMonitor creates the inotify instance.

func (*Monitor) Add

func (m *Monitor) Add(name, path string) (int64, error)

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) Close

func (m *Monitor) Close() error

Close releases the inotify instance.

func (*Monitor) Fd

func (m *Monitor) Fd() int

Fd exposes the inotify descriptor so a caller can wait on it with its own event loop rather than blocking in Read.

func (*Monitor) Read

func (m *Monitor) Read() ([]Event, error)

Read drains the pending inotify events and returns the resulting changes.

It returns an empty slice and no error when nothing is pending, since the descriptor is non-blocking.

func (*Monitor) Value

func (m *Monitor) Value(name string) (int64, bool)

Value returns the last known value of a tracked file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL