agent

package
v0.14.6 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package agent implements `rdpanel agent`: it runs next to (as the parent of) hbbr on a relay host, enrolls with the central panel using a one-time token, keeps an outbound ed25519-authenticated WebSocket session to <panel>/agent/v1/connect, persists the desired hbbr config it receives, applies it through hbbr's loopback admin channel (the hbbr half of the panel's reconciler, unchanged) and reports status. See docs/relay-agents.md.

Index

Constants

View Source
const (
	KeyFile    = "agent.key"
	StateFile  = "agent-state.json"
	HealthFile = "agent-health.json"
)

Files in the agent data directory.

Variables

View Source
var ErrNoKey = errors.New("agent: no hbbs public key yet; hbbr is not started")

ErrNoKey refuses to start hbbr without an explicit hbbs public key: `-k _` or no key would make hbbr generate a foreign key pair on a fresh host.

View Source
var ErrTokenRejected = errors.New("agent: the panel rejected the enrollment token (invalid, expired or already used); create a new one in the panel")

ErrTokenRejected means the panel refused the enrollment token.

Functions

func CheckHealth

func CheckHealth(dir string, now time.Time, maxAge time.Duration) error

CheckHealth reads the health file: it must be fresh, and hbbr must be up whenever it should run.

func LoadOrCreateKey

func LoadOrCreateKey(dir string) (ed25519.PrivateKey, bool, error)

LoadOrCreateKey returns the agent's ed25519 identity from dir/agent.key (base64 of the 32-byte seed, 0600), generating it on first start.

func SaveState

func SaveState(dir string, st State) error

SaveState writes dir/agent-state.json atomically (0600).

Types

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent is one running relay agent.

func New

func New(cfg Config) (*Agent, error)

New prepares an agent: data dir, identity key and persisted state.

func (*Agent) ApplyNow

func (a *Agent) ApplyNow(ctx context.Context)

ApplyNow runs one forced apply pass (tests).

func (*Agent) Run

func (a *Agent) Run(ctx context.Context) error

Run enrolls if needed and then runs until ctx ends.

func (*Agent) State

func (a *Agent) State() State

State returns a copy of the persisted state.

func (*Agent) Supervisor

func (a *Agent) Supervisor() *Supervisor

Supervisor exposes the hbbr supervisor (tests).

type Config

type Config struct {
	// PanelURL is the panel's public (client API) base URL.
	PanelURL string
	// EnrollToken is the one-time token; ignored once enrolled.
	EnrollToken string
	// DataDir holds agent.key, agent-state.json and hbbr's list files.
	DataDir string
	// HBBRBin is the hbbr executable.
	HBBRBin string
	// RelayPort is hbbr's TCP port (its loopback admin channel too).
	RelayPort int
	// PanelCA is an optional PEM file with extra CAs to trust for the panel.
	PanelCA string
	// Hostname overrides the reported host name.
	Hostname string
	// StatusInterval is how often status is reported (default 10 s).
	StatusInterval time.Duration
	// ApplyInterval is the drift-check period (default 15 s).
	ApplyInterval time.Duration
	Log           *slog.Logger

	// Test hooks.
	Runner     Runner
	HTTPClient *http.Client
	// ControlAddr overrides the hbbr admin address (default 127.0.0.1:RelayPort).
	ControlAddr string
	// ProcDir is /proc (host sampling).
	ProcDir string
	// MaxBackoff caps reconnect delays (default 60 s).
	MaxBackoff time.Duration
	// HealthInterval is how often agent-health.json is written (default 10 s).
	HealthInterval time.Duration
}

Config configures the agent (environment: see FromEnv).

func FromEnv

func FromEnv(lookup func(string) (string, bool)) (Config, error)

FromEnv reads the agent configuration from RDPANEL_AGENT_* variables.

type ExecRunner

type ExecRunner struct {
	Bin string
	Dir string
	Log *slog.Logger
}

ExecRunner runs a real hbbr binary in Dir (where it reads blacklist.txt/blocklist.txt). Output lines are logged with an "hbbr" source.

func (ExecRunner) Start

func (r ExecRunner) Start(_ context.Context, args []string) (Process, error)

Start implements Runner.

type Health

type Health struct {
	Time      time.Time `json:"time"`
	Connected bool      `json:"connected"`
	// Run is the desired hbbr state; HBBRUp the observed one.
	Run    bool `json:"run"`
	HBBRUp bool `json:"hbbr_up"`
}

Health is written to dir/agent-health.json for `rdpanel agent health`.

type Process

type Process interface {
	PID() int
	// Wait blocks until the process exits.
	Wait() error
	// Stop asks the process to exit (SIGTERM) and kills it after grace.
	Stop(grace time.Duration)
}

Process is a running hbbr.

type Runner

type Runner interface {
	Start(ctx context.Context, args []string) (Process, error)
}

Runner starts hbbr processes (injectable for tests).

type State

type State struct {
	PanelURL  string             `json:"panel_url"`
	AgentID   int64              `json:"agent_id"`
	RelayName string             `json:"relay_name,omitempty"`
	Config    *agentproto.Config `json:"config,omitempty"`
}

State is persisted across restarts: the agent keeps enforcing its last config while the panel is unreachable.

func LoadState

func LoadState(dir string) (State, error)

LoadState reads dir/agent-state.json (zero State when missing).

type Supervisor

type Supervisor struct {

	// MinBackoff/MaxBackoff bound restart delays; StableAfter resets them.
	MinBackoff, MaxBackoff, StableAfter time.Duration
	// contains filtered or unexported fields
}

Supervisor runs hbbr as a child process and restarts it with backoff. It is deliberately small and independent of the WebSocket session, so a session problem never touches running relays (design §5.1, option 1).

func NewSupervisor

func NewSupervisor(r Runner, port int, log *slog.Logger) *Supervisor

NewSupervisor builds a supervisor for hbbr on port.

func (*Supervisor) Restart

func (s *Supervisor) Restart()

Restart restarts a running hbbr (the "restart-hbbr" command).

func (*Supervisor) Run

func (s *Supervisor) Run(ctx context.Context)

Run supervises until ctx ends; hbbr is stopped on return.

func (*Supervisor) Set

func (s *Supervisor) Set(key string, run bool)

Set changes the desired state: run hbbr with key, or stop it.

func (*Supervisor) Started

func (s *Supervisor) Started() <-chan struct{}

Started fires after every hbbr start (the agent then re-applies its config).

func (*Supervisor) Status

func (s *Supervisor) Status() agentproto.HBBRStatus

Status returns the hbbr status.

Jump to

Keyboard shortcuts

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