pkg

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2025 License: GPL-3.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AllowedFacts = map[string]struct{}{
	"platform":           {},
	"user":               {},
	"inventory_hostname": {},
	"ssh_host_pub_keys":  {},
}

Facts that can be gathered by the setup module

View Source
var SpecialVars = []string{
	"previous",
}

Don't look for dependencies for these vars

Functions

func ConvertOutputToFactsMap

func ConvertOutputToFactsMap(output ModuleOutput) interface{}

func EvaluateExpression

func EvaluateExpression(s string, closure *Closure) (interface{}, error)

func ExecuteGraph

func ExecuteGraph(executor GraphExecutor, graph Graph, inventoryFile string, cfg *config.Config) error

func GetHostContexts

func GetHostContexts(inventory *Inventory) (map[string]*HostContext, error)

func GetOrderedGraph

func GetOrderedGraph(cfg *config.Config, graph Graph) ([][]Task, error)

func GetVariableUsage

func GetVariableUsage(task Task) ([]string, error)

func GetVariableUsageFromModule

func GetVariableUsageFromModule(input ConcreteModuleInputProvider) ([]string, error)

func GetVariableUsageFromTemplate

func GetVariableUsageFromTemplate(s string) []string

func GetVariablesFromExpression

func GetVariablesFromExpression(jinjaString string) []string

func Indent

func Indent(n int) string

func InitializeRecapStats

func InitializeRecapStats(hostContexts map[string]*HostContext) map[string]map[string]int

func MapToSyncMap

func MapToSyncMap(m map[string]interface{}) *sync.Map

Helper function to convert map[string]interface{} to *sync.Map

func PPrintOutput

func PPrintOutput(output ModuleOutput, err error)

PPrintOutput prints the output of a module or an error in a readable format.

func ParseLoop

func ParseLoop(task Task, c *HostContext) ([]interface{}, error)

ParseLoop parses the loop directive of a task, evaluating expressions and returning items to iterate over.

func PrepareLevelHistoryAndGetCount

func PrepareLevelHistoryAndGetCount(
	tasksInLevel []Task,
	hostContexts map[string]*HostContext,
	executionLevel int,
) (map[string]chan Task, int, error)

func ReadLocalFile

func ReadLocalFile(filename string) (string, error)

func ReadTemplateFile

func ReadTemplateFile(filename string) (string, error)

func RegisterModule

func RegisterModule(name string, module Module)

RegisterModule allows modules to register themselves by name.

func RegisterVariableIfNeeded

func RegisterVariableIfNeeded(result TaskResult, task Task, c *Closure)

func ResolveExecutionLevel

func ResolveExecutionLevel(taskName string, dependsOn map[string][]string, executedOnStep map[string]int) map[string]int

func RevertTasksWithConfig

func RevertTasksWithConfig(
	executedTasks []map[string]chan Task,
	hostContexts map[string]*HostContext,
	cfg *config.Config,
) error

RevertTasksWithConfig orchestrates the revert process for executed tasks.

func TemplateString

func TemplateString(s string, closure *Closure) (string, error)

TemplateString processes a Jinja2 template string with provided variables.

Types

type Closure

type Closure struct {
	HostContext *HostContext
	ExtraFacts  map[string]interface{}
}

func ConstructClosure

func ConstructClosure(c *HostContext, t Task) *Closure

func GetTaskClosures

func GetTaskClosures(task Task, c *HostContext) ([]*Closure, error)

GetTaskClosures generates one or more Closures for a task, handling loops.

func TempClosureForHost

func TempClosureForHost(h *Host) *Closure

func (*Closure) GetFact

func (c *Closure) GetFact(key string) (interface{}, bool)

func (*Closure) GetFacts

func (c *Closure) GetFacts() map[string]interface{}

type ConcreteModuleInputProvider

type ConcreteModuleInputProvider interface {
	ToCode() string
	GetVariableUsage() []string
	Validate() error
	// HasRevert indicates if this input defines a revert action.
	HasRevert() bool
	// ProvidesVariables returns a list of variable names this input might define (e.g., keys in set_fact).
	ProvidesVariables() []string
}

ModuleInput is a marker interface for module input parameters. It ensures that module parameters have a method to generate their code representation.

func TemplateModuleInputFields

func TemplateModuleInputFields(originalProvider ConcreteModuleInputProvider, closure *Closure) (ConcreteModuleInputProvider, error)

TemplateModuleInputFields creates a *copy* of the input provider's underlying struct, walking all string fields in the copied struct (recursively) and templates them. The original input struct is NOT mutated. It accepts a ConcreteModuleInputProvider and returns a new ConcreteModuleInputProvider of the same underlying kind (value or pointer) as the input, or an error.

type FactProvider

type FactProvider interface {
	AsFacts() map[string]interface{}
}

FactProvider is an interface that module outputs can implement to provide a map representation suitable for registering as facts.

type Graph

type Graph struct {
	RequiredInputs []string
	Tasks          [][]Task
}

func CompileGraphForHost

func CompileGraphForHost(graph Graph, host Host) (Graph, error)

Compile the graph for a specific host by replacing variables with host-specific values. This is useful for generating a binary for a specific host, where it can be used directly without the need of an inventory file. It's as simple as downloading the binary and running it.

func CompilePlaybookForHost

func CompilePlaybookForHost(graph Graph, inventoryFile, hostname string) (Graph, error)

func NewGraph

func NewGraph(nodes []GraphNode) (Graph, error)

func NewGraphFromFile

func NewGraphFromFile(path string) (Graph, error)

func NewGraphFromPlaybook

func NewGraphFromPlaybook(data []byte) (Graph, error)

func (Graph) CheckInventoryForRequiredInputs

func (g Graph) CheckInventoryForRequiredInputs(inventory *Inventory) error

func (Graph) ParallelTasks

func (g Graph) ParallelTasks() [][]Task

Order tasks based on execution level

func (Graph) SaveToFile

func (g Graph) SaveToFile(path string) error

func (Graph) SaveToTemporalWorkflowFile

func (g Graph) SaveToTemporalWorkflowFile(path string) error

func (Graph) SequentialTasks

func (g Graph) SequentialTasks() [][]Task

Order tasks by their id

func (Graph) String

func (g Graph) String() string

func (Graph) ToCode

func (g Graph) ToCode() string

type GraphExecutor

type GraphExecutor interface {
	Execute(hostContexts map[string]*HostContext, orderedGraph [][]Task, cfg *config.Config) error
	Revert(executedTasks []map[string]chan Task, hostContexts map[string]*HostContext, cfg *config.Config) error
}

GraphExecutor defines the interface for running a Spage graph.

type GraphNode

type GraphNode interface {
	String() string
	ToCode() string
}

GraphNode represents either a list of tasks or a nested graph

func TextToGraphNodes

func TextToGraphNodes(blocks []map[string]interface{}) ([]GraphNode, error)

type Group

type Group struct {
	Hosts map[string]*Host       `yaml:"hosts"`
	Vars  map[string]interface{} `yaml:"vars"`
}

type Host

type Host struct {
	Name    string
	Host    string `yaml:"host"`
	Vars    map[string]interface{}
	Groups  map[string]string `yaml:"groups"`
	IsLocal bool
}

func (*Host) Prepare

func (h *Host) Prepare()

func (Host) String

func (h Host) String() string

type HostContext

type HostContext struct {
	Host    *Host
	Facts   *sync.Map
	History *sync.Map
	// contains filtered or unexported fields
}

func GetDelegatedHostContext

func GetDelegatedHostContext(task Task, hostContexts map[string]*HostContext, closure *Closure) (*HostContext, error)

func InitializeHostContext

func InitializeHostContext(host *Host) (*HostContext, error)

func (*HostContext) Close

func (c *HostContext) Close() error

func (*HostContext) Copy

func (c *HostContext) Copy(src, dst string) error

func (*HostContext) ReadFile

func (c *HostContext) ReadFile(filename string, username string) (string, error)

func (*HostContext) ReadFileBytes

func (c *HostContext) ReadFileBytes(filename string, username string) ([]byte, error)

func (*HostContext) RunCommand

func (c *HostContext) RunCommand(command, username string) (string, string, error)

func (*HostContext) SetFileMode

func (c *HostContext) SetFileMode(path, mode, username string) error

func (*HostContext) Stat

func (c *HostContext) Stat(path string, follow bool) (os.FileInfo, error)

Stat retrieves file info. For remote hosts, it uses SFTP Lstat (no follow). For local hosts, it uses os.Stat (follow=true) or os.Lstat (follow=false).

func (*HostContext) WriteFile

func (c *HostContext) WriteFile(filename, contents, username string) error

type IgnoredTaskError

type IgnoredTaskError struct {
	OriginalErr error
}

IgnoredTaskError is a custom error type used when a task fails but IgnoreErrors is set to true. It wraps the original error.

func (*IgnoredTaskError) Error

func (e *IgnoredTaskError) Error() string

Error implements the error interface for IgnoredTaskError.

func (*IgnoredTaskError) Unwrap

func (e *IgnoredTaskError) Unwrap() error

Unwrap allows errors.Is and errors.As to work with the wrapped original error.

type Inventory

type Inventory struct {
	Hosts  map[string]*Host       `yaml:"all"`
	Vars   map[string]interface{} `yaml:"vars"`
	Groups map[string]*Group      `yaml:"groups"`
}

func LoadInventory

func LoadInventory(path string) (*Inventory, error)

func (Inventory) GetContextForHost

func (i Inventory) GetContextForHost(host *Host) (*HostContext, error)

func (Inventory) GetContextForRun

func (i Inventory) GetContextForRun() (map[string]*HostContext, error)

func (Inventory) GetHostByName

func (i Inventory) GetHostByName(name string) (*Host, error)

func (Inventory) GetInitialFactsForHost

func (i Inventory) GetInitialFactsForHost(host *Host) map[string]interface{}

GetInitialFactsForHost gathers and layers facts for a specific host from the inventory. It applies global inventory vars, then group vars, then host-specific vars.

type LocalGraphExecutor

type LocalGraphExecutor struct {
	Runner TaskRunner
}

LocalGraphExecutor provides common logic for executing a Spage graph. It relies on a TaskRunner to perform the actual execution of individual tasks.

func NewLocalGraphExecutor

func NewLocalGraphExecutor(runner TaskRunner) *LocalGraphExecutor

NewLocalGraphExecutor creates a new LocalGraphExecutor with the given TaskRunner.

func (*LocalGraphExecutor) Execute

func (e *LocalGraphExecutor) Execute(hostContexts map[string]*HostContext, orderedGraph [][]Task, cfg *config.Config) error

Execute implements the main execution loop for a Spage graph.

func (*LocalGraphExecutor) Revert

func (e *LocalGraphExecutor) Revert(executedTasks []map[string]chan Task, hostContexts map[string]*HostContext, cfg *config.Config) error

type Module

type Module interface {
	InputType() reflect.Type
	OutputType() reflect.Type
	Execute(params ConcreteModuleInputProvider, c *Closure, runAs string) (ModuleOutput, error)
	Revert(params ConcreteModuleInputProvider, c *Closure, previous ModuleOutput, runAs string) (ModuleOutput, error)
	ParameterAliases() map[string]string
}

func GetModule

func GetModule(name string) (Module, bool)

GetModule retrieves a registered module by name.

type ModuleInput

type ModuleInput struct {
	// Actual holds the concrete *ShellInput, *CopyInput, etc.
	// Let the standard marshalers handle this field when marshaling the parent Task struct,
	// using the custom Task MarshalJSON.
	Actual ConcreteModuleInputProvider `json:"actual,omitempty" yaml:"actual,omitempty"`
}

Its primary role is to facilitate correct JSON/YAML marshaling/unmarshaling when it's a field within another struct (like Task).

func (*ModuleInput) GetVariableUsage

func (mi *ModuleInput) GetVariableUsage() []string

GetVariableUsage delegates to the Actual ConcreteModuleInputProvider.

func (*ModuleInput) HasRevert

func (mi *ModuleInput) HasRevert() bool

HasRevert delegates to the Actual ConcreteModuleInputProvider.

func (*ModuleInput) ProvidesVariables

func (mi *ModuleInput) ProvidesVariables() []string

ProvidesVariables delegates to the Actual ConcreteModuleInputProvider.

func (*ModuleInput) ToCode

func (mi *ModuleInput) ToCode() string

ToCode delegates to the Actual ConcreteModuleInputProvider. It's called during code generation, Actual must be populated.

func (*ModuleInput) Validate

func (mi *ModuleInput) Validate() error

Validate delegates to the Actual ConcreteModuleInputProvider.

type ModuleOutput

type ModuleOutput interface {
	Changed() bool
	String() string
}

ModuleOutput is a marker interface for module output results. It ensures that module results can indicate whether they represent a change.

type RevertableChange

type RevertableChange[T comparable] struct {
	Before T
	After  T
}

func (RevertableChange[T]) Changed

func (r RevertableChange[T]) Changed() bool

type Task

type Task struct {
	Id           int         `yaml:"id" json:"id"`
	Name         string      `yaml:"name" json:"name"`
	Module       string      `yaml:"module" json:"module"`
	Params       ModuleInput `yaml:"params" json:"params"`
	Validate     string      `yaml:"validate" json:"validate,omitempty"`
	Before       string      `yaml:"before" json:"before,omitempty"`
	After        string      `yaml:"after" json:"after,omitempty"`
	When         string      `yaml:"when" json:"when,omitempty"`
	Register     string      `yaml:"register" json:"register,omitempty"`
	RunAs        string      `yaml:"run_as" json:"run_as,omitempty"`
	IgnoreErrors bool        `yaml:"ignore_errors,omitempty" json:"ignore_errors,omitempty"`
	FailedWhen   string      `yaml:"failed_when,omitempty" json:"failed_when,omitempty"`
	ChangedWhen  string      `yaml:"changed_when,omitempty" json:"changed_when,omitempty"`
	Loop         interface{} `yaml:"loop,omitempty" json:"loop,omitempty"`
	DelegateTo   string      `yaml:"delegate_to,omitempty" json:"delegate_to,omitempty"`
}

func (Task) ExecuteModule

func (t Task) ExecuteModule(closure *Closure) TaskResult

func (Task) MarshalJSON

func (t Task) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface for Task. This ensures that the Params field is marshaled correctly by handling the Actual field.

func (Task) RevertModule

func (t Task) RevertModule(closure *Closure) TaskResult

func (Task) ShouldExecute

func (t Task) ShouldExecute(closure *Closure) bool

func (Task) String

func (t Task) String() string

func (Task) ToCode

func (t Task) ToCode() string

func (*Task) UnmarshalJSON

func (t *Task) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for Task.

func (*Task) UnmarshalYAML

func (t *Task) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML implements the yaml.Unmarshaler interface for Task.

type TaskResult

type TaskResult struct {
	Output   ModuleOutput
	Error    error // This can now be nil, a normal error, or an IgnoredTaskError
	Closure  *Closure
	Task     Task
	Duration time.Duration
	Status   TaskStatus
	Failed   bool
	Changed  bool
	// ExecutionSpecificOutput can store runner-specific results, e.g., SpageActivityResult for Temporal.
	ExecutionSpecificOutput interface{}
}

Useful for having a single type to pass around in channels

func HandleResult

func HandleResult(r *TaskResult, t Task, c *Closure) TaskResult

type TaskRunner

type TaskRunner interface {
	ExecuteTask(ctx context.Context, task Task, closure *Closure, cfg *config.Config) TaskResult
	RevertTask(ctx context.Context, task Task, closure *Closure, cfg *config.Config) TaskResult
}

TaskRunner defines an interface for how a single task is executed. This allows the core execution logic to be generic, while the actual task dispatch (local, Temporal activity, etc.) can be specific.

type TaskStatus

type TaskStatus string
const (
	TaskStatusSkipped TaskStatus = "skipped"
	TaskStatusFailed  TaskStatus = "failed"
	TaskStatusChanged TaskStatus = "changed"
	TaskStatusOk      TaskStatus = "ok"
)

func (TaskStatus) String

func (s TaskStatus) String() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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