Help us shape the future of Go! Take the 2026 Go Developer Survey

cli

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package cli turns the agent's typed ops into HAProxy runtime commands and runs them against the worker stats socket. It knows command strings and success strings; it makes no decisions and parses no configuration.

Index

Constants

View Source
const PayloadTerminator = "HAPTIC"

PayloadTerminator ends a payload block. HAProxy's default terminator is an empty line, which a blank line inside a certificate or a map would trip; a custom pattern (max 7 characters) is what makes the content irrelevant to the framing.

View Source
const VersionPlaceholder = "\x01ver\x01"

VersionPlaceholder stands in for the map version `prepare map` allocates. The executor substitutes it in the rest of the program once the allocating command answered.

Variables

View Source
var (
	// ErrNameCollision means a backend of that name already exists. The shape
	// behind the name is unreadable at runtime, so the apply stops and reloads.
	ErrNameCollision = errors.New("backend name already in use")
	// ErrWaitExpired means the object still has attached connections.
	ErrWaitExpired = errors.New("wait delay expired")
	// ErrRejected is HAProxy refusing a command.
	ErrRejected = errors.New("haproxy rejected the command")
	// ErrUnreadableResponse means the batch answered something the matcher
	// cannot attribute. The baseline is unknown from here on.
	ErrUnreadableResponse = errors.New("unreadable runtime response")
)

Typed outcomes the caller acts on rather than just reports.

View Source
var ErrDeferralOverflow = errors.New("deferred delete queue is full")

ErrDeferralOverflow means the queue is at its cap: the caller must reload instead of deferring more deletes.

View Source
var ErrTooManyEntries = errors.New("runtime listing exceeds the entry limit")

ErrTooManyEntries means a listing is above the agent's limit, which is a refusal to read it, not a statement about what the worker holds.

View Source
var ErrUnknownOp = errors.New("unknown op kind")

ErrUnknownOp is what an op kind this agent does not execute wraps. The server refuses the whole batch and falls back to a reload.

View Source
var ErrUnsafeToken = errors.New("unsafe runtime token")

ErrUnsafeToken is what every negative-space rejection wraps. A token that reaches HAProxy unchecked can split the command line and run a second command, so the check is a refusal, never a sanitisation.

View Source
var ErrWorkerGone = errors.New("the deferred delete's HAProxy worker has changed")

ErrWorkerGone means a deferred attempt no longer addresses its original worker.

Functions

func Kinds

func Kinds() []string

Kinds lists the op kinds this agent executes, for /v1/state.agent_ops.

Types

type Client

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

Client is the agent's runtime plumbing.

func New

func New(ctx context.Context, cfg Config) (*Client, error)

New wires both sockets without probing them: readiness is the server's job, and the agent must come up before HAProxy answers.

func (*Client) Execute

func (c *Client) Execute(programs []Program) ([]api.OpResult, error)

Execute runs the programs of one apply in the order the controller composed them and returns one result per program. It stops at the first failure: the caller's answer to a rejected op is to reload the desired set, which makes the commands after the failure irrelevant.

func (*Client) FrontendConnections

func (c *Client) FrontendConnections(ignore map[string]bool) (uint64, error)

FrontendConnections sums the cumulative accepted-connection counter of every frontend except the ignored ones. It is the drain's signal: the sum stops moving once nothing routes new connections to the worker any more.

func (*Client) Info

func (c *Client) Info() (api.HAProxyInfo, error)

Info reads the worker's process ID and microsecond-resolution start time.

func (*Client) Inventory

func (c *Client) Inventory(generation uint64) (api.Inventory, error)

Inventory reads what the running worker has loaded. The controller needs it to know whether a certificate or map it wants to touch at runtime exists at all; a path that is not in here is structural.

func (*Client) MapEntries

func (c *Client) MapEntries(path string) (map[string][]string, error)

MapEntries reads back one map file's runtime contents, keyed by map key. Duplicate keys keep every value, in insertion order, because that is what decides which one a lookup wins.

func (*Client) Raw

func (c *Client) Raw(command string) (string, error)

Raw runs one command on the worker socket with the experimental prefix.

func (*Client) Reload

func (c *Client) Reload() (string, error)

Reload asks the master to re-exec. The returned string is HAProxy's startup log, which is what a NACK carries back to the operator.

func (*Client) ServerNames

func (c *Client) ServerNames(backend string) (map[string]struct{}, error)

ServerNames reads the servers the running worker holds for a backend.

func (*Client) ShowProc

func (c *Client) ShowProc() (string, error)

ShowProc asks the master process for its worker table. It is the master socket's readiness gate and nothing else.

type Command

type Command struct {
	// Text is the command line. It never contains a newline, so a batch can
	// join commands with ';'.
	Text string
	// Payload is the block a "<<" command carries. A command with a payload is
	// always the last one on its line.
	Payload string
	// Expect is the substring HAProxy answers on success, matched
	// case-insensitively. Empty means success is any response that is not an
	// error.
	Expect string
	// Capture marks the command whose response carries the map version the rest
	// of the program substitutes into VersionPlaceholder.
	Capture bool
	// Repeat marks a command that has to run until HAProxy refuses it: `del map`
	// removes one duplicate per call on 3.4 and all of them on 3.0.
	Repeat bool
	// Optional marks the session prefix, whose response is version-dependent
	// and must never be mistaken for an op's verdict.
	Optional bool
}

Command is one HAProxy runtime command with the framing and the verdict rule that belong to it.

type CommandResult

type CommandResult struct {
	Output string
	Err    error
}

CommandResult is one command's verdict, with HAProxy's own words.

type Config

type Config struct {
	WorkerSocket string
	MasterSocket string
	Logger       *slog.Logger
}

Config names the worker and master sockets the agent talks to.

type Content

type Content func(path string) ([]byte, error)

Content supplies the on-disk bytes of a manifest path for the ops that push a whole file through the socket.

type Deferrals

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

Deferrals drains the delete tail of an apply off the apply path: `wait …-removable` blocks for as long as a client keeps a connection, and no apply may pay that.

func NewDeferrals

func NewDeferrals(client *Client, logger *slog.Logger, observer Observer) *Deferrals

NewDeferrals builds the queue. observer may be nil.

func (*Deferrals) Check

func (d *Deferrals) Check(servers []ServerRef, backends []string) error

Check validates a batch without making it visible to the drainer.

func (*Deferrals) Enqueue

func (d *Deferrals) Enqueue(worker api.HAProxyInfo, servers []ServerRef, backends []string) error

Enqueue commits deletes only after their inline traffic-stopping ops succeed.

func (*Deferrals) Pending

func (d *Deferrals) Pending() api.PendingDeletes

Pending reports what is still to happen, for /v1/state: the queue plus the delete the drain is inside, which is outstanding until it reports back.

func (*Deferrals) SetWorker

func (d *Deferrals) SetWorker(worker api.HAProxyInfo)

SetWorker retires queued work; in-flight commands stay on their old connection.

func (*Deferrals) Start

func (d *Deferrals) Start(ctx context.Context) error

Start drains the queue until the context ends. The ticker is what picks up requeued deletes: a server whose client will not let go is retried on the next tick, never in a spin.

func (*Deferrals) Wake

func (d *Deferrals) Wake()

Wake drains committed deletes without waiting for the next tick.

type Observer

type Observer interface {
	DeferredDeleteDone(kind string)
	DeferredDeleteDeferred(kind string)
	// DeferredDeleteAbandoned is a delete the agent gave up on: the object
	// stays until the next reload, which is a distinct fact from "retrying".
	DeferredDeleteAbandoned(kind string)
	DeferredDeleteSuperseded(kind string)
}

Observer receives deferred-delete outcomes so the server can export them.

type Program

type Program struct {
	Kind     string
	Commands []Command
	Abort    []Command
}

Program is the command sequence of one typed op, plus the cleanup that has to run when one of its commands fails. An open `set ssl cert` transaction wedges that certificate until a reload, so the abort is not optional.

func Compile

func Compile(op *api.Op, content Content) (Program, error)

Compile turns one typed op into its program. Every string that reaches HAProxy passes the negative-space check first.

type ServerRef

type ServerRef struct {
	Backend string `json:"backend"`
	Server  string `json:"server"`
}

ServerRef names one server of one backend.

func Split

func Split(ops []api.Op) (inline []api.Op, servers []ServerRef, backends []string)

Split separates the ops an apply runs inline from the deletes that block on `wait`. The controller composes the full A4 sequence; the agent runs the traffic-stopping half now and the removal half later.

func (ServerRef) String

func (r ServerRef) String() string

String renders the reference the way HAProxy addresses it.

Jump to

Keyboard shortcuts

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