renderplan

package
v0.6.0 Latest Latest
Warning

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

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

Documentation

Overview

Package renderplan holds the structure a render declares about its own output: the ordered sections of haproxy.cfg, the backend records the generator emitted them from, the map entries, and the file set.

The structure is produced by the generator (chart macros through pkg/controller/rendercontext.PlanRegistry), never by parsing HAProxy configuration. Pure data: no controller, templating or client-native imports.

Index

Constants

View Source
const (
	SectionKindCore    = "core"
	SectionKindProfile = "profile"
	SectionKindBackend = "backend"
)

Section kinds.

View Source
const (
	ShapeDynamic    = "dynamic"
	ShapeStructural = "structural"
)

Backend shapes: a dynamic backend can be created and populated over the runtime API, a structural one needs a reload.

View Source
const (
	FileKindConfig  = "config"
	FileKindMap     = "map"
	FileKindCert    = "cert"
	FileKindCA      = "ca"
	FileKindCRTList = "crtlist"
	FileKindGeneral = "general"
)

File kinds.

View Source
const ConfigFilePath = "haproxy.cfg"

ConfigFilePath is the single main configuration path in every render plan.

View Source
const SchemaVersion = 1

SchemaVersion identifies the plan format. A consumer reading a foreign version must treat the plan as unknown rather than decode it partially.

Variables

View Source
var ErrDocumentTransitionRequiresRebuild = errors.New("render plan document transition requires a full rebuild")

ErrDocumentTransitionRequiresRebuild reports a transition the sparse delta protocol cannot encode.

Functions

func Digest

func Digest(b []byte) string

Digest returns the xxhash64 of b as fixed-width hex. It is the only hash the plan uses, so digests from different producers are comparable.

func DigestString

func DigestString(s string) string

DigestString is Digest over a string, without copying it to a byte slice.

func EqualKeywordArgs

func EqualKeywordArgs(left, right []KeywordArg) bool

EqualKeywordArgs reports whether both keyword lists declare the same keywords with the same arguments in the same order. Nil and empty lists are the same list.

func ExactlyEqual

func ExactlyEqual(left, right *Plan) bool

ExactlyEqual compares the complete render identity without trusting a digest. It returns false when either plan came from a blob and therefore no longer carries the controller-local exact bytes.

func FormatDigest

func FormatDigest(sum uint64) string

FormatDigest renders an xxhash64 sum as the plan's 16-character hex digest.

func MapEntriesMatch

func MapEntriesMatch(content string, entries []Entry) bool

MapEntriesMatch reports whether ParseMapEntries(content) would equal entries, without building the entry list: it walks the lines and compares each parsed entry in place.

func ReconcileSnapshotWithBackendSource

func ReconcileSnapshotWithBackendSource(
	authority *Authority,
	previous *Snapshot,
	plan *Plan,
	backends BackendSource,
	document rendercontent.Document,
) (*Snapshot, *Delta, error)

ReconcileSnapshotWithBackendSource is ReconcileSnapshotWithConfigDocument with the backends read from source; plan.Backends must be nil. A previous snapshot built from an earlier state of the same source is compared over the names that changed since, not over every backend.

func ReconcileSnapshotWithConfigDocument

func ReconcileSnapshotWithConfigDocument(
	authority *Authority,
	previous *Snapshot,
	plan *Plan,
	document rendercontent.Document,
) (*Snapshot, *Delta, error)

ReconcileSnapshotWithConfigDocument owns exact plan metadata while retaining config as a document.

Types

type Authority

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

Authority owns one lineage of render-plan snapshots. digestFallbacks is a pointer so a shallow copy of an authority stays a copyable value, which authentication still rejects.

func NewAuthority

func NewAuthority() *Authority

NewAuthority creates an isolated snapshot lineage.

func (*Authority) DigestFallbacks

func (a *Authority) DigestFallbacks() uint64

DigestFallbacks counts the plan digests this lineage computed by rebuilding the whole plan because the streaming canonical writer could not prove its order. It stays zero while the incremental digest engages.

func (*Authority) ValidateAuthentication

func (a *Authority) ValidateAuthentication() error

ValidateAuthentication verifies the authority's exact identity.

func (*Authority) ValidateSnapshot

func (a *Authority) ValidateSnapshot(snapshot *Snapshot) error

ValidateSnapshot proves that snapshot belongs to this authority.

type Backend

type Backend struct {
	Name          string       `json:"name"`
	Profile       string       `json:"profile,omitempty"`
	Mode          string       `json:"mode,omitempty"`
	GUID          string       `json:"guid,omitempty"`
	Balance       string       `json:"balance,omitempty"`
	HashType      string       `json:"hashType,omitempty"`
	Shape         string       `json:"shape"`
	ShapeReason   string       `json:"shapeReason,omitempty"`
	Servers       []Server     `json:"servers,omitempty"`
	DefaultServer []KeywordArg `json:"defaultServer,omitempty"`

	BodyDigest     string `json:"bodyDigest"`
	CommentsDigest string `json:"commentsDigest"`
	RecordDigest   string `json:"recordDigest"`
	TextDigest     string `json:"textDigest"`

	Body         []string `json:"-"`
	Comments     []string `json:"-"`
	ContentKnown bool     `json:"-"`
}

Backend is the record a generator macro declared alongside the backend section text it emitted.

func (*Backend) EqualContent

func (b *Backend) EqualContent(other *Backend) bool

EqualContent reports whether both backends carry the same text description: the body, comment and record digests, the body and comment lines, and whether the content is known. TextDigest is left to the caller, since it changes with every render that re-emits the section.

func (*Backend) EqualRecord

func (b *Backend) EqualRecord(other *Backend) bool

EqualRecord reports whether both backends declare the same record: every field that describes the backend itself rather than its text. The digests, the body and comment lines and ContentKnown describe the text and are compared by EqualContent. A plan with thousands of backends compares every one per deployment, so this is field by field rather than reflective.

type BackendHandle

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

BackendHandle proves one exact backend record.

type BackendSource

type BackendSource interface {
	// Token identifies the source's state; the snapshot built from it keeps
	// the token and offers it to the next transition. It must be comparable
	// (a pointer, or nil), since snapshots compare tokens with ==.
	Token() any
	// ChangedSince lists every name whose entry may differ from the state
	// token identifies. ok is false when the source cannot tell, and the
	// transition then compares every backend.
	ChangedSince(token any) (names []string, ok bool)
	// Get returns the backend by name; ContentKnown is true on every backend
	// the source returns.
	Get(name string) (Backend, bool)
	Len() int
	// Walk visits every backend in an unspecified order.
	Walk(func(name string, backend Backend) error) error
}

BackendSource hands a document transition the plan's backends by name, so a transition from a snapshot built from an earlier state of the same source compares only the names that changed in between instead of every backend.

type CRTList

type CRTList struct {
	Path    string         `json:"path"`
	Entries []CRTListEntry `json:"entries,omitempty"`
}

CRTList is the entry list of one crt-list file, declared by the generator that emitted the file.

type CRTListEntry

type CRTListEntry struct {
	Cert       string       `json:"cert"`
	Options    []KeywordArg `json:"options,omitempty"`
	SNIFilters []string     `json:"sniFilters,omitempty"`
}

CRTListEntry is one crt-list line: the certificate, its ssl options and the SNI filters that select it.

type CRTListHandle

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

CRTListHandle proves one exact CRT-list record.

type Changes

type Changes struct {
	Sections []SequenceChange[Section]
	Backends []NamedChange[Backend]
	Profiles []NamedChange[Profile]
	Maps     []NamedChange[Map]
	CRTLists []NamedChange[CRTList]
	Files    []FileChange
}

Changes is the exact changed-record set carried by a Delta.

type CurrentConfig

type CurrentConfig struct {
	ServerIndex map[string]map[string]ServerAddr `json:"serverIndex"`
}

CurrentConfig is the client-native-free view of the running configuration that templates read as `currentConfig`.

type Delta

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

Delta is an authenticated transition between exact plan roots.

func (*Delta) Apply

func (d *Delta) Apply(base *Snapshot) (*Snapshot, error)

Apply returns this delta's next root only for its exact base.

func (*Delta) Changes

func (d *Delta) Changes() (Changes, error)

Changes returns detached copies of only the records changed by this delta.

func (*Delta) RequiresFullValidation

func (d *Delta) RequiresFullValidation() (bool, error)

RequiresFullValidation reports structural changes not safe for local validation.

func (*Delta) SameRoot

func (d *Delta) SameRoot() (bool, error)

SameRoot reports whether no plan record changed.

func (*Delta) SectionChanges

func (d *Delta) SectionChanges() ([]SequenceChange[Section], error)

SectionChanges validates the complete delta and returns detached section changes.

func (*Delta) ValidateAuthentication

func (d *Delta) ValidateAuthentication() error

ValidateAuthentication verifies the exact transition and every changed record.

type Entry

type Entry struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

Entry is one map-file line: the key and the rest of the line.

func ParseMapEntries

func ParseMapEntries(content string) []Entry

ParseMapEntries splits rendered map-file content into entries: the first field is the key, the rest of the line the value. Blank and comment lines are dropped; duplicate keys are kept in order, because HAProxy map lookups are a multiset and a delta over them must see every occurrence.

This reads HAPTIC's own output format, not HAProxy configuration.

type File

type File struct {
	Path           string `json:"path"`
	Kind           string `json:"kind"`
	ReloadOnChange bool   `json:"reloadOnChange"`
	Digest         string `json:"digest"`
	Size           int64  `json:"size"`

	Content      string `json:"-"`
	ContentKnown bool   `json:"-"`
}

File is one file the render produced.

type FileChange

type FileChange struct {
	Index  int
	Before *FileRecord
	After  *FileRecord
}

FileChange is one exact file transition. Nil means absent.

type FileDescriptor

type FileDescriptor struct {
	Path           string
	Kind           string
	ReloadOnChange bool
	Size           int64
}

FileDescriptor is plan-file metadata available without materializing content.

type FileGapHandle

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

FileGapHandle proves one exact insertion gap in the file sequence.

type FileHandle

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

FileHandle proves one exact file and its sequence position.

type FileRecord

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

FileRecord is an authenticated immutable plan-file value.

func (*FileRecord) ConfigDocument

func (r *FileRecord) ConfigDocument() (rendercontent.Document, bool, error)

ConfigDocument returns the retained config document when this record has one.

func (*FileRecord) Descriptor

func (r *FileRecord) Descriptor() (FileDescriptor, error)

Descriptor returns file identity and size without materializing its content.

func (*FileRecord) LegacyCopy

func (r *FileRecord) LegacyCopy() (File, error)

LegacyCopy materializes a detached compatibility file.

type KeywordArg

type KeywordArg struct {
	Name string   `json:"name"`
	Args []string `json:"args,omitempty"`
}

KeywordArg is a server or default-server keyword with its arguments, structured so no consumer has to scan the emitted line.

type Map

type Map struct {
	Path    string  `json:"path"`
	Ordered bool    `json:"ordered"`
	Entries []Entry `json:"entries,omitempty"`
}

Map is the entry list of one map file, derived from its rendered content.

type MapHandle

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

MapHandle proves one exact map record.

type NamedChange

type NamedChange[T any] struct {
	Name   string
	Before *T
	After  *T
}

NamedChange is one keyed record transition. Nil means absent.

type ParsedMapEntries

type ParsedMapEntries struct {
	Content string
	Entries []Entry
	// contains filtered or unexported fields
}

ParsedMapEntries is a map file's entries with the text they came from, so the next version of the text parses only the lines that changed. Every entry's key and value are substrings of Content and of nothing older: a carried entry is re-sliced into the new text, or the text of every version whose lines survive would stay alive behind it.

func ParseMapEntriesIndexed

func ParseMapEntriesIndexed(content string) ParsedMapEntries

ParseMapEntriesIndexed is ParseMapEntries keeping what Reparse needs.

func (ParsedMapEntries) Reparse

func (p ParsedMapEntries) Reparse(content string) ParsedMapEntries

Reparse parses content, reusing the entries of every line that is unchanged at the head and at the tail of the previous text. An entry depends only on its own line, so only the lines between the two are parsed again.

type Plan

type Plan struct {
	SchemaVersion int                `json:"schemaVersion"`
	ID            string             `json:"id"`
	Sections      []Section          `json:"sections"`
	Backends      map[string]Backend `json:"backends"`
	Profiles      map[string]Profile `json:"profiles"`
	Maps          map[string]Map     `json:"maps"`
	CRTLists      map[string]CRTList `json:"crtLists,omitempty"`
	Files         []File             `json:"files"`
}

Plan is the immutable structure of one render.

func (*Plan) Canonical

func (p *Plan) Canonical() []byte

Canonical returns the deterministic JSON encoding of the plan with the ID cleared, so the ID can be a digest over it. encoding/json sorts map keys and keeps struct fields in declaration order.

func (*Plan) Clone

func (p *Plan) Clone() *Plan

Clone returns an independently owned copy of the plan.

func (*Plan) ComputeID

func (p *Plan) ComputeID()

ComputeID sets the plan ID to the digest of its canonical encoding.

func (*Plan) CurrentConfig

func (p *Plan) CurrentConfig() CurrentConfig

CurrentConfig projects the plan's backend servers into the shape templates read as `currentConfig`.

type Profile

type Profile struct {
	Name       string `json:"name"`
	BodyDigest string `json:"bodyDigest"`
	HasRules   bool   `json:"hasRules,omitempty"`
}

Profile is a named defaults section shared by backends.

type ProfileHandle

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

ProfileHandle proves one exact profile record.

type Section

type Section struct {
	Kind       string `json:"kind"`
	Name       string `json:"name"`
	TextDigest string `json:"textDigest"`
	Length     int    `json:"length"`

	Text      string `json:"-"`
	TextKnown bool   `json:"-"`
}

Section is one contiguous run of haproxy.cfg. The sections of a plan partition the file: concatenating their text reproduces it byte for byte.

type SectionGapHandle

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

SectionGapHandle proves one exact insertion gap in the section sequence.

type SectionHandle

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

SectionHandle proves one exact section and its emission position.

type SequenceChange

type SequenceChange[T any] struct {
	Index  int
	Before *T
	After  *T
}

SequenceChange is one ordered record transition. Nil means absent.

type Server

type Server struct {
	Name     string       `json:"name"`
	Address  string       `json:"address"`
	Port     int          `json:"port"`
	Weight   *int         `json:"weight,omitempty"` // nil: no weight keyword; 0 is a real weight
	Disabled bool         `json:"disabled,omitempty"`
	GUID     string       `json:"guid,omitempty"`
	Comment  string       `json:"comment,omitempty"`
	Extra    []KeywordArg `json:"extra,omitempty"`
}

Server is one server line, declared as data.

func (*Server) Equal

func (s *Server) Equal(other *Server) bool

Equal reports whether both servers declare the same line.

type ServerAddr

type ServerAddr struct {
	Address string
	Port    *int64
}

ServerAddr is one server's address as templates see it. Port is a pointer because a server line may omit it and templates dereference it.

type Snapshot

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

Snapshot is an authenticated immutable final render plan.

func NewSnapshot

func NewSnapshot(authority *Authority, plan *Plan, previous *Snapshot) (*Snapshot, error)

NewSnapshot deeply owns plan and reuses exact roots from previous.

func NewSnapshotWithConfigDocument

func NewSnapshotWithConfigDocument(
	authority *Authority,
	plan *Plan,
	document rendercontent.Document,
	previous *Snapshot,
) (*Snapshot, error)

NewSnapshotWithConfigDocument owns plan while retaining config as a document.

func (*Snapshot) BackendHandle

func (s *Snapshot) BackendHandle(name string) (*BackendHandle, bool, error)

BackendHandle returns a proof for name when present.

func (*Snapshot) BackendNamed

func (s *Snapshot) BackendNamed(name string) (Backend, bool, error)

BackendNamed returns a detached exact backend by name.

func (*Snapshot) CRTListHandle

func (s *Snapshot) CRTListHandle(path string) (*CRTListHandle, bool, error)

CRTListHandle returns a proof for path when present.

func (*Snapshot) ExactEqual

func (s *Snapshot) ExactEqual(other *Snapshot) (bool, error)

ExactEqual compares complete local plan content; IDs never authorize equality.

func (*Snapshot) FileAt

func (s *Snapshot) FileAt(index int) (File, error)

FileAt returns a detached exact file by emission rank.

func (*Snapshot) FileGapHandle

func (s *Snapshot) FileGapHandle(index int) (*FileGapHandle, error)

FileGapHandle returns a proof for the file insertion gap at index.

func (*Snapshot) FileHandle

func (s *Snapshot) FileHandle(index int) (*FileHandle, error)

FileHandle returns a proof for the file at index.

func (*Snapshot) ID

func (s *Snapshot) ID() (string, error)

ID returns the plan's immutable render identifier.

func (*Snapshot) LegacyCopy

func (s *Snapshot) LegacyCopy() (*Plan, error)

LegacyCopy materializes a fully detached Plan compatibility value.

func (*Snapshot) Len

func (s *Snapshot) Len() (int, error)

Len returns the number of top-level collection entries.

func (*Snapshot) MapHandle

func (s *Snapshot) MapHandle(path string) (*MapHandle, bool, error)

MapHandle returns a proof for path when present.

func (*Snapshot) MapNamed

func (s *Snapshot) MapNamed(path string) (Map, bool, error)

MapNamed returns a detached exact map by path.

func (*Snapshot) MarshalJSON

func (s *Snapshot) MarshalJSON() ([]byte, error)

MarshalJSON preserves the canonical fragments and falls back when their order is unproven.

func (*Snapshot) ProfileHandle

func (s *Snapshot) ProfileHandle(name string) (*ProfileHandle, bool, error)

ProfileHandle returns a proof for name when present.

func (*Snapshot) ProfileNamed

func (s *Snapshot) ProfileNamed(name string) (Profile, bool, error)

ProfileNamed returns a detached exact profile by name.

func (*Snapshot) SameRoot

func (s *Snapshot) SameRoot(other *Snapshot) (bool, error)

SameRoot reports exact authenticated root identity.

func (*Snapshot) SectionAt

func (s *Snapshot) SectionAt(index int) (Section, error)

SectionAt returns a detached exact section by emission rank.

func (*Snapshot) SectionGapHandle

func (s *Snapshot) SectionGapHandle(index int) (*SectionGapHandle, error)

SectionGapHandle returns a proof for the section insertion gap at index.

func (*Snapshot) SectionHandle

func (s *Snapshot) SectionHandle(index int) (*SectionHandle, error)

SectionHandle returns a proof for the section at index.

func (*Snapshot) SectionsCopy

func (s *Snapshot) SectionsCopy() ([]Section, error)

SectionsCopy returns detached ordered section metadata without materializing config.

func (*Snapshot) SharedPlan

func (s *Snapshot) SharedPlan() (*Plan, error)

SharedPlan is the snapshot's Plan as a read-only view, built once per snapshot: its records alias the sealed entries, which every reader of a plan must leave alone. A caller that changes a plan takes LegacyCopy. Materialising a detached copy per deployment deep-copied every backend before any pod was touched.

func (*Snapshot) ValidateAuthentication

func (s *Snapshot) ValidateAuthentication() error

ValidateAuthentication verifies the private root in constant time.

func (*Snapshot) WriteJSON

func (s *Snapshot) WriteJSON(target io.Writer) error

WriteJSON writes the complete encoding only after authentication and canonicalization succeed.

type Transaction

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

Transaction atomically path-copies changes from one exact plan root.

func BeginTransaction

func BeginTransaction(authority *Authority, base *Snapshot) (*Transaction, error)

BeginTransaction starts an atomic edit against base.

func (*Transaction) Commit

func (t *Transaction) Commit() (*Snapshot, *Delta, error)

Commit seals the next snapshot and its exact base-to-next proof.

func (*Transaction) DeleteBackend

func (t *Transaction) DeleteBackend(expected *BackendHandle) error

DeleteBackend removes an exact backend and requires full output validation.

func (*Transaction) DeleteFile

func (t *Transaction) DeleteFile(expected *FileHandle) error

DeleteFile removes an exact file and requires full output validation.

func (*Transaction) DeleteMap

func (t *Transaction) DeleteMap(expected *MapHandle) error

DeleteMap removes an exact map and requires full output validation.

func (*Transaction) DeleteProfile

func (t *Transaction) DeleteProfile(expected *ProfileHandle) error

DeleteProfile removes an exact profile and requires full output validation.

func (*Transaction) DeleteSection

func (t *Transaction) DeleteSection(expected *SectionHandle) error

DeleteSection removes an exact section and requires full output validation.

func (*Transaction) InsertBackend

func (t *Transaction) InsertBackend(name string, backend Backend) error

InsertBackend inserts a new keyed backend and requires full output validation.

func (*Transaction) InsertFile

func (t *Transaction) InsertFile(expected *FileGapHandle, file File) error

InsertFile inserts a file at an exact gap and requires full output validation.

func (*Transaction) InsertMap

func (t *Transaction) InsertMap(path string, value Map) error

InsertMap inserts a new keyed map and requires full output validation.

func (*Transaction) InsertProfile

func (t *Transaction) InsertProfile(name string, profile Profile) error

InsertProfile inserts a new keyed profile and requires full output validation.

func (*Transaction) InsertSection

func (t *Transaction) InsertSection(expected *SectionGapHandle, section Section) error

InsertSection inserts a section at an exact gap and requires full output validation.

func (*Transaction) ReplaceBackend

func (t *Transaction) ReplaceBackend(expected *BackendHandle, backend Backend) error

ReplaceBackend changes only the exact backend proven by expected.

func (*Transaction) ReplaceCRTList

func (t *Transaction) ReplaceCRTList(expected *CRTListHandle, value CRTList) error

ReplaceCRTList changes only the exact CRT-list proven by expected.

func (*Transaction) ReplaceConfigFileDocument

func (t *Transaction) ReplaceConfigFileDocument(
	expected *FileHandle,
	document rendercontent.Document,
) error

ReplaceConfigFileDocument replaces the config file without materializing its content.

func (*Transaction) ReplaceFile

func (t *Transaction) ReplaceFile(expected *FileHandle, file File) error

ReplaceFile changes only the exact file proven by expected.

func (*Transaction) ReplaceMap

func (t *Transaction) ReplaceMap(expected *MapHandle, value Map) error

ReplaceMap changes only the exact map proven by expected.

func (*Transaction) ReplaceProfile

func (t *Transaction) ReplaceProfile(expected *ProfileHandle, profile Profile) error

ReplaceProfile changes only the exact profile proven by expected.

func (*Transaction) ReplaceSection

func (t *Transaction) ReplaceSection(expected *SectionHandle, section Section) error

ReplaceSection changes only the exact section proven by expected.

Jump to

Keyboard shortcuts

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