bossbox

package module
v0.0.0-...-b681e62 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2023 License: MIT Imports: 8 Imported by: 0

README

BoxBoss is a library for managing the state of machines, comparable to tools like Ansible or Salt but solving some paintpoints with those tools.

Boxboss will be a daemon that listens for events to trigger specific configuration modules. If it's managing the state of a file, it uses inotify to watch that file, and fix it as soon as it it changes, so it can never be out of compliance. If it's managing a service, it will listen for service events in dbus and keep that service in the correct state. This solves the scheduling problem.

Boxboss doesn't use config files. It is a library and scaffolding to build your own binaries. This menas that states can be mocked and tested in CI/CD, and allows for repsenting complex dependencies that can't be reasonably done in a config file.

This is an early WIP.

Documentation

Overview

package bossbox includes the Module interface which should be implemented by plugins, and Manager which manages a module and it's hooks

Index

Constants

This section is empty.

Variables

View Source
var ErrApplyFailed = errors.New("apply failed")
View Source
var ErrChangesRequiredFailed = errors.New("changes-required hook error")
View Source
var ErrCheckFailed = errors.New("check failed")
View Source
var ErrCondition = errors.New("condition hook error")

ErrCondition is returned by the module when a Condition errors.

This will wrap the actual error returned by the condition, and will itself be wrapped in an ErrPreCheckHook, because a condition is a PreCheckHook.

View Source
var ErrConditionNotMet = errors.New("condition not met")

ErrConditionNotMet signals that a precheck condition was not met and the module should not run, but did not error in an unexpected way.

This error is not propegated to Apply, Apply will return nil if a ConditionNotMet is returned from a PreCheckHook.

View Source
var ErrNotRun = errors.New("module has not yet run")

ErrNotRun indicates that the Runner has not been Applied.

View Source
var ErrPostCheckHook = errors.New("PostCheck hook error")

ErrPostCheckHook is returned if a PostCheckHook errors causing the Apply to error

View Source
var ErrPreCheckHook = errors.New("PreCheck hook error")

ErrPreCheckHook is returned if a PreCheckHook errors. It will wrap underlying errors.

View Source
var ErrTriggerDepthExceeded = errors.New("trigger depth exceeded")

Functions

func Log

func Log() *slog.Logger

func SetLogHandler

func SetLogHandler(handler slog.Handler)

func WithHookName

func WithHookName(name string) func(context.Context) context.Context

func WithMaxTriggerDepth

func WithMaxTriggerDepth(max int) func(context.Context) context.Context

WithMaxTriggerDepth sets the maximum trigger depth allowed in this context. If a hook from one Manage() calls another Manage(), this will increase the trigger depth by one. Default limit is 10

func WithTriggerId

func WithTriggerId(trigger slog.LogValuer) func(context.Context) context.Context

WithTriggerId will return a context with an identifier for the trigger that is used to trigger a Manager.Manage(), useful for logging

Types

type Manager

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

Manager launches a goroutine to accept addition and removal of hooks, and applies the module whenever Manage is called. A Manager is safe for concurrent use by multiple goroutines.

func NewManager

func NewManager(module Module) *Manager

NewManager creates the runner that will run, listening for triggers from Apply until ctx is canceled.

It will run until ctx is canceled. Attempting to use the Manager after context is canceled will likely cause deadlocks.

func (*Manager) AddChangesRequiredHook

func (s *Manager) AddChangesRequiredHook(ctx context.Context, f func(context.Context) error, config ...func(context.Context) context.Context) error

AddChangesRequiredHook adds a function that is run after the check step, only if changes are required.

func (*Manager) AddCondition

func (s *Manager) AddCondition(ctx context.Context, f func(context.Context) (conditionMet bool, err error), config ...func(context.Context) context.Context) error

AddCondition adds a function that is a condition to determine whether or not Check should run.

If conditionMet returns false, any concurrently running PreCheckHook contexts will be canceled, and the module will not be applied. But Apply will not return an error.

AddCondition returns a function that can be used to remove the hook.

func (*Manager) AddPostChangesHook

func (s *Manager) AddPostChangesHook(ctx context.Context, f func(ctx context.Context), config ...func(context.Context) context.Context) error

AddPostChangesHook adds a PostRunHook that is run after a successful module run that made changes.

func (*Manager) AddPostCheckHook

func (s *Manager) AddPostCheckHook(ctx context.Context, f func(ctx context.Context, changeNeeded bool) error, config ...func(context.Context) context.Context) error

AddPostCheckHook adds a function that is run after the Check step

This is useful for actions that need to be run in preperation. For example a file management module may neeed A service to be stopped before the file can be managed.

An error in this hook will propegate to the Apply and prevent Run from running.

If multiple PostCheckHooks are specified, they will run concurrently, and an error from any will cancel the contexts of the remaining PostCheckHooks. The first error will be returned.

AddPostCheckHook returns a function that can be used to remove the hook.

func (*Manager) AddPostErrorHook

func (s *Manager) AddPostErrorHook(ctx context.Context, f func(ctx context.Context, err error), config ...func(context.Context) context.Context) error

AddPostErrorHook adds a PostRunHook that is run after a module run errors.

func (*Manager) AddPostRunHook

func (s *Manager) AddPostRunHook(ctx context.Context, f func(ctx context.Context, changed bool, err error), config ...func(context.Context) context.Context) error

AddPostRunHook adds a function that is run at the end of the execution. This will run regardless of the source of any errors. The function is responsible for checking the type of error.

PostRunHooks do not block returning the result. This means that a subsequent run could run the PostRunHook before the previous one finished.

AddPostRunHook returns a function that can be used to remove the hook.

func (*Manager) AddPostSuccessHook

func (s *Manager) AddPostSuccessHook(ctx context.Context, f func(ctx context.Context, changes bool), config ...func(context.Context) context.Context) error

AddPostSuccessHook adds a PostRunHook that is run after a successful module run.

func (*Manager) AddPreCheckHook

func (s *Manager) AddPreCheckHook(ctx context.Context, f func(context.Context) error, config ...func(context.Context) context.Context) error

AddPreCheckHook adds a function that is run before the Check step

An error in this hook will propegate to the Apply and prevent Check or Run from running, except for ErrConditionNotMet.

If multiple PreCheckHooks are specified, they will run concurrently, and an error from any will cancel the contexts of the remaining PreCheckHooks. The first error will be returned.

func (*Manager) ChangesRequire

func (s *Manager) ChangesRequire(ctx context.Context, r *Manager, config ...func(context.Context) context.Context) error

ChangesRequire requires r as a requirement that runs only if changes are indicated by s.Check

func (*Manager) ChangesTriggers

func (s *Manager) ChangesTriggers(ctx context.Context, r *Manager, config ...func(context.Context) context.Context) error

ChangesTriggers triggers r anytime s successfully makes changes

func (*Manager) ErrorTriggers

func (s *Manager) ErrorTriggers(ctx context.Context, r *Manager, config ...func(context.Context) context.Context) error

ErrorTriggers triggers r anytime s errors

func (*Manager) LogValue

func (s *Manager) LogValue() slog.Value

func (*Manager) Manage

func (s *Manager) Manage(ctx context.Context, config ...func(context.Context) context.Context) (changed bool, err error)

Manage will apply the module.

Multiple request to Manage will be queued.

func (*Manager) Require

func (s *Manager) Require(ctx context.Context, r *Manager, config ...func(context.Context) context.Context) error

Require sets r as a requirement that must be successful before s can be applied

func (*Manager) RequireChanges

func (s *Manager) RequireChanges(ctx context.Context, r *Manager, config ...func(context.Context) context.Context) error

RequireChanges sets r as a condition and only runs s if r made changes

func (*Manager) SuccessTriggers

func (s *Manager) SuccessTriggers(ctx context.Context, r *Manager, config ...func(context.Context) context.Context) error

SuccessTriggers triggers r when s.Apply is successful

func (*Manager) Triggers

func (s *Manager) Triggers(ctx context.Context, r *Manager, config ...func(context.Context) context.Context) error

Triggers triggers r anytime s is run (regardless of success or changes)

func (*Manager) Wait

func (s *Manager) Wait(ctx context.Context) error

Wait will block until any hook addition or removals, or applications are complete

func (*Manager) WaitAll

func (s *Manager) WaitAll(ctx context.Context) error

WaitAll waits for hook additions or removals, applications, and any currently running post-run hooks

type Module

type Module interface {
	// Name is a name identifying the module, used in logging. The type is logged independently. So this should uniquely identify this instance.
	// For example, a file module should use the name of the file being managed.
	Name() string

	// Check reports whether changes are required. If no changes are required, Apply will not be called by the StateRunner.
	//
	// The context provided to check will be done when after any post-run hooks are complete, so cleanup tasks required by a state
	// can be done using an afterFunc to the context
	Check(context.Context) (bool, error)

	// Apply makes modifications to the system bringing it into compliance. Reports whether changes were made during the process.
	//
	// A warning will be logged if Check indicated changes were required, but Apply reports no changes were made.
	Apply(context.Context) (bool, error)

	// Manage returns a Manager for this module
	Manage() *Manager
}

Module interface is the interface that a module must implement.

type State

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

State is a simple implementation of the Module interface.

func NewState

func NewState(name string, check func(context.Context) (bool, error), run func(context.Context) (bool, error)) *State

func (*State) Apply

func (s *State) Apply(ctx context.Context) (bool, error)

func (*State) Check

func (s *State) Check(ctx context.Context) (bool, error)

func (*State) Manage

func (s *State) Manage() *Manager

func (*State) Name

func (s *State) Name() string

Directories

Path Synopsis
modules
file
Package file provides file management modules
Package file provides file management modules

Jump to

Keyboard shortcuts

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