Documentation
¶
Overview ¶
Package files owns the manifest-managed file tree of an HAProxy pod: the mount probe, tree hashing, part verification, the backup journal and the transactional write. Disk is the authority; nothing here parses HAProxy syntax.
Package files owns the manifest-managed file tree of an HAProxy pod: the mount probe, tree hashing, part verification, the backup journal and the transactional write. Disk is the authority; nothing here parses HAProxy syntax.
Index ¶
- Constants
- Variables
- func ValidatePath(rel string) error
- type Entry
- type EntryKind
- type Fingerprint
- type Journal
- type Mount
- type Observation
- type Staged
- type Store
- func (s *Store) Abs(rel string) (string, error)
- func (s *Store) BaseDir() string
- func (s *Store) Begin(j *Journal, configRel string) *Transaction
- func (s *Store) ClearJournal(j *Journal) error
- func (s *Store) CrossDeviceCopies() uint64
- func (s *Store) HashTree(paths []string) (map[string]api.FileAt, error)
- func (s *Store) Mounts() []Mount
- func (s *Store) Observe(paths []string) (map[string]Observation, error)
- func (s *Store) Restore(j *Journal, configRel string) error
- func (s *Store) Stage(rel string, r io.Reader, digest string, size int64) (*Staged, error)
- func (s *Store) StagePatch(rel string, r io.Reader, patch *api.FilePatch, digest string, size int64) (*Staged, error)
- func (s *Store) SweepTemp() error
- type Transaction
Constants ¶
const ( TempDirName = ".haptic-tmp" LKGDirName = ".haptic-lkg" )
Directory names the agent reserves inside every mount it writes to.
Variables ¶
var ErrDigestMismatch = errors.New("part does not match its manifest digest")
ErrDigestMismatch is what a received part failing its manifest digest wraps; it is a refusal, never a retry.
var ErrInvalidPath = fmt.Errorf("invalid manifest path")
ErrInvalidPath is the class every path rejection wraps, so a caller can report one refusal reason for the whole safety check.
var ErrPatchBaseMissing = errors.New("patch base is not the file held")
ErrPatchBaseMissing is what a patch wraps when the file on disk is not the base it splices into; the controller answers it by sending the whole file.
Functions ¶
func ValidatePath ¶
ValidatePath accepts only paths the agent may own: relative, canonical, and with no dot-prefixed component, which keeps the agent's own state file, its temp directories and its LKG directories out of every manifest.
Types ¶
type Entry ¶
type Entry struct {
Path string `json:"path"`
Kind EntryKind `json:"kind"`
Backup string `json:"backup,omitempty"`
}
Entry is one path's backup record. Backup is an absolute path inside the path's own mount, empty for KindCreated.
type EntryKind ¶
type EntryKind string
EntryKind is how a path looked when the last-known-good set still held it.
type Fingerprint ¶
Fingerprint tells the file the agent wrote from a rewrite of it: its bytes, by SHA-256 rather than the digest anyone can collide, its mode and its owner.
type Journal ¶
type Journal struct {
Entries []Entry `json:"entries,omitempty"`
}
Journal holds the last-known-good version of every path changed since the LKG plan. The first entry per path wins: later applies must not overwrite a backup with an already-diverged version.
type Mount ¶
Mount is one filesystem under the base directory. Hardlinks and renames are confined to a single mount, so temp and LKG directories exist per mount.
type Observation ¶
type Observation struct {
At api.FileAt
Fingerprint Fingerprint
}
Observation is one file of the tree as read back from disk.
type Staged ¶
type Staged struct {
Rel string
Fingerprint Fingerprint
// contains filtered or unexported fields
}
Staged is a verified part waiting in its target mount's temp directory.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store owns the manifest-managed tree under a base directory.
func NewStore ¶
NewStore probes the mounts under baseDir and prepares each one's temp and LKG directory. reserved names the paths inside the tree that belong to something other than the manifest, which is the HAProxy sockets.
func (*Store) Begin ¶
func (s *Store) Begin(j *Journal, configRel string) *Transaction
Begin opens a transaction whose rollback target is the journal's contents. configRel is installed last so the tree is never a config newer than the files it references.
func (*Store) ClearJournal ¶
ClearJournal drops the backups of a set that has become the last known good.
func (*Store) CrossDeviceCopies ¶
CrossDeviceCopies counts renames that fell back to a copy. The mount probe is supposed to keep this at zero; the server reports a non-zero count as an invariant violation.
func (*Store) HashTree ¶
HashTree observes the ownership set on disk. A path that is absent, or that something else turned into a directory or a symlink, is not in the result: it is not a file the agent wrote, and its absence is what makes a plan id unknown after a container restart put the bootstrap config back.
func (*Store) Observe ¶
func (s *Store) Observe(paths []string) (map[string]Observation, error)
Observe is HashTree with each file's fingerprint.
func (*Store) Restore ¶
Restore puts the last-known-good version of every journalled path back. The config file goes last so HAProxy is never told to read a config whose auxiliary files have not been restored yet.
func (*Store) Stage ¶
Stage streams a received part into the temp directory of the mount that will hold it and verifies it against the manifest digest and size before the content can ever reach the tree.
func (*Store) StagePatch ¶
func (s *Store) StagePatch(rel string, r io.Reader, patch *api.FilePatch, digest string, size int64) (*Staged, error)
StagePatch stages a file delivered as a splice: r carries the bytes that replace [patch.Offset, patch.Offset+patch.Length) of the file at rel, which has to be on disk at patch.BaseDigest and patch.BaseSize, and the result is verified against digest and size exactly as a whole part is. A base that is not held is ErrPatchBaseMissing; a patch that does not fit its base is a refusal.
type Transaction ¶
type Transaction struct {
// contains filtered or unexported fields
}
Transaction is one apply's file work: back up what it is about to change, then install the staged parts and drop the paths the manifest no longer names. It never runs a runtime command and never reloads.
func (*Transaction) Backup ¶
func (t *Transaction) Backup() error
Backup records the last-known-good version of every path the transaction touches. It is the first phase that can fail, and it changes no content.
func (*Transaction) Changes ¶
func (t *Transaction) Changes() int
Changes counts the paths this transaction touches.
func (*Transaction) Delete ¶
func (t *Transaction) Delete(rel string)
Delete schedules the removal of a path the manifest dropped.
func (*Transaction) Discard ¶
func (t *Transaction) Discard()
Discard drops every staged part that has not been installed. The tree is untouched by a discarded transaction.
func (*Transaction) Install ¶
func (t *Transaction) Install(staged *Staged)
Install schedules a verified part.
func (*Transaction) Write ¶
func (t *Transaction) Write() error
Write installs the staged parts, config last, and then drops the deleted paths. A failure leaves the journal complete, so the caller can restore.