pluginmgr

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2026 License: EUPL-1.2 Imports: 22 Imported by: 0

Documentation

Overview

Package plugin implements infrastructure adapters for the plugin system.

The plugin package provides concrete implementations for plugin discovery, loading, validation, registration, and lifecycle management. It enables AWF workflows to extend functionality through external RPC-based plugins (operations, filters, transformers) without modifying core code. The package handles manifest parsing, version compatibility checking, state persistence, and operation registry integration.

Architecture Role

In the hexagonal architecture:

  • Implements plugin loading and lifecycle management (infrastructure adapters)
  • Provides OperationRegistry for runtime operation lookup and registration
  • Integrates with domain/ports.CommandExecutor for plugin discovery
  • Application layer orchestrates workflow execution via registered plugin operations
  • Domain layer defines operation contracts without plugin coupling

All plugin components use atomic file operations and thread-safe registries to support concurrent plugin loading during workflow initialization. The manifest parser validates semver constraints and capability declarations before plugin activation.

Plugin Management

## RPCPluginManager (rpc_manager.go)

Plugin lifecycle orchestration:

  • Discover: Scan plugins directory for valid manifests
  • Load: Initialize plugin RPC client and register operations
  • Init: Call plugin initialization hook with configuration
  • Shutdown: Gracefully stop a running plugin
  • ShutdownAll: Cleanup all active plugins on process termination
  • Get: Retrieve loaded plugin by name
  • List: Enumerate active plugin names

## Loader (loader.go)

Plugin discovery and validation:

  • DiscoverPlugins: Find plugin.awf manifests in plugins directory
  • LoadPlugin: Parse manifest, validate constraints, prepare RPC client
  • ValidatePlugin: Check manifest schema, version compatibility, capability declarations

Registry and Discovery

## OperationRegistry (registry.go)

Runtime operation registration and lookup:

  • RegisterOperation: Add plugin-provided operation (thread-safe)
  • UnregisterOperation: Remove operation by name
  • GetOperation: Retrieve operation implementation by name
  • GetPluginOperations: List operations provided by a plugin
  • UnregisterPluginOperations: Remove all operations from a plugin
  • Count: Total registered operations
  • Clear: Reset registry state

Manifest and Metadata

## ManifestParser (manifest_parser.go)

Plugin metadata parsing:

  • ParseManifest: Read plugin.awf YAML manifest
  • Validates: name, version, awf_version (semver constraints), capabilities
  • Supports metadata: author, description, license, homepage

Capabilities: operation, filter, transform (plugin feature declarations)

State Persistence

## JSONPluginStateStore (state_store.go)

Plugin state persistence:

  • Save: Write plugin state to JSON file (atomic via temp file + rename)
  • Load: Read plugin state from JSON file
  • SetEnabled: Enable/disable plugin by name
  • IsEnabled: Check if plugin is enabled
  • GetConfig: Retrieve plugin-specific configuration
  • SetConfig: Update plugin-specific configuration
  • GetState: Access full plugin state
  • ListDisabled: Enumerate disabled plugins

Uses file locking to prevent concurrent modification during workflow execution.

Version Handling

## Version (version.go)

Semantic versioning support:

  • ParseVersion: Parse semver string (e.g., "1.2.3")
  • ParseConstraint: Parse version constraint (e.g., ">=1.0.0", "~1.2", "^2.0")
  • CheckVersionConstraint: Validate version against constraint
  • IsCompatible: Check plugin compatibility with AWF version
  • Compare: Semver comparison (major.minor.patch)

Operators: =, !=, >, >=, <, <=, ~ (tilde range), ^ (caret range)

Index

Constants

View Source
const (
	OpEqual          = "==" // Exact match
	OpNotEqual       = "!=" // Not equal
	OpGreater        = ">"  // Greater than
	OpGreaterOrEqual = ">=" // Greater than or equal
	OpLess           = "<"  // Less than
	OpLessOrEqual    = "<=" // Less than or equal
	OpTilde          = "~"  // Compatible with (allows patch updates)
	OpCaret          = "^"  // Compatible with (allows minor updates)
)

Version comparison operators supported by the constraint parser.

View Source
const DefaultPluginsDir = "plugins"

Default plugins directory relative to config.

View Source
const ManifestFileName = "plugin.yaml"

ManifestFileName is the expected filename for plugin manifests.

Variables

View Source
var (
	ErrOperationAlreadyRegistered = errors.New("operation already registered")
	ErrOperationNotFound          = errors.New("operation not found")
	ErrInvalidOperation           = errors.New("invalid operation schema")
)

Registry errors.

View Source
var ErrNoPluginsConfigured = errors.New("rpc_manager: no plugins configured")

ErrNoPluginsConfigured indicates no plugin loader or directory is configured.

Functions

func CheckVersionConstraint

func CheckVersionConstraint(constraintStr, versionStr string) (bool, error)

CheckVersionConstraint checks if a version string satisfies a constraint string. This is the main entry point for version compatibility checking.

func IsCompatible

func IsCompatible(awfVersionConstraint, currentAWFVersion string) (bool, error)

IsCompatible checks if the current AWF version is compatible with a plugin's AWF version constraint. This is a convenience function.

Types

type CompositeOperationProvider

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

CompositeOperationProvider wraps multiple OperationProvider instances into a single provider, delegating GetOperation/ListOperations/Execute by operation name. Enables coexistence of multiple built-in providers (e.g., github and notify).

func NewCompositeOperationProvider

func NewCompositeOperationProvider(providers ...ports.OperationProvider) *CompositeOperationProvider

NewCompositeOperationProvider creates a new composite operation provider that delegates to the given providers.

func (*CompositeOperationProvider) Execute

Execute runs a plugin operation by delegating to the appropriate provider.

func (*CompositeOperationProvider) GetOperation

GetOperation returns an operation by name from the first provider that has it.

func (*CompositeOperationProvider) ListOperations

ListOperations returns all available operations from all providers.

type Constraint

type Constraint struct {
	Operator string  // One of the Op* constants
	Version  Version // The version to compare against
}

Constraint represents a single version constraint (e.g., ">=0.4.0").

func ParseConstraint

func ParseConstraint(s string) (Constraint, error)

ParseConstraint parses a constraint string into a Constraint struct. Accepts formats: ">=0.4.0", "~1.2.0", "^2.0.0", "1.0.0" (implies ==)

func (Constraint) Check

func (c Constraint) Check(v Version) bool

Check tests if a version satisfies this constraint.

type Constraints

type Constraints []Constraint

Constraints represents multiple version constraints that all must be satisfied.

func ParseConstraints

func ParseConstraints(s string) (Constraints, error)

ParseConstraints parses a constraint string that may contain multiple constraints. Constraints are separated by spaces or commas. Examples: ">=0.4.0 <1.0.0", ">=0.4.0, <1.0.0"

func (Constraints) Check

func (cs Constraints) Check(v Version) bool

Check tests if a version satisfies all constraints.

func (Constraints) String

func (cs Constraints) String() string

String returns the string representation of the constraints.

type FileSystemLoader

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

FileSystemLoader implements PluginLoader for filesystem-based plugin discovery.

func NewFileSystemLoader

func NewFileSystemLoader(parser *ManifestParser) *FileSystemLoader

NewFileSystemLoader creates a new FileSystemLoader with the given manifest parser.

func (*FileSystemLoader) DiscoverPlugins

func (l *FileSystemLoader) DiscoverPlugins(ctx context.Context, pluginsDir string) ([]*pluginmodel.PluginInfo, error)

DiscoverPlugins scans a directory for plugins and returns their info. Each subdirectory containing a plugin.yaml is considered a plugin.

func (*FileSystemLoader) LoadPlugin

func (l *FileSystemLoader) LoadPlugin(ctx context.Context, pluginDir string) (*pluginmodel.PluginInfo, error)

LoadPlugin loads a single plugin from a directory path. Reads the plugin.yaml manifest and creates PluginInfo with status=StatusLoaded.

func (*FileSystemLoader) ValidatePlugin

func (l *FileSystemLoader) ValidatePlugin(info *pluginmodel.PluginInfo) error

ValidatePlugin checks if a discovered plugin is valid and compatible. Validates manifest fields, capabilities, and AWF version constraint.

type JSONPluginStateStore

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

JSONPluginStateStore persists plugin states to a JSON file. Implements ports.PluginStateStore interface.

func NewJSONPluginStateStore

func NewJSONPluginStateStore(basePath string) *JSONPluginStateStore

NewJSONPluginStateStore creates a new JSONPluginStateStore.

func (*JSONPluginStateStore) BasePath

func (s *JSONPluginStateStore) BasePath() string

BasePath returns the storage directory path.

func (*JSONPluginStateStore) GetConfig

func (s *JSONPluginStateStore) GetConfig(name string) map[string]any

GetConfig returns the stored configuration for a plugin. Returns nil if plugin has no stored configuration.

func (*JSONPluginStateStore) GetState

GetState returns the full state for a plugin, or nil if not found.

func (*JSONPluginStateStore) IsEnabled

func (s *JSONPluginStateStore) IsEnabled(name string) bool

IsEnabled returns whether a plugin is enabled. Returns true for unknown plugins (enabled by default).

func (*JSONPluginStateStore) ListDisabled

func (s *JSONPluginStateStore) ListDisabled() []string

ListDisabled returns names of all explicitly disabled plugins.

func (*JSONPluginStateStore) Load

Load reads plugin states from storage.

func (*JSONPluginStateStore) Save

Save persists all plugin states to storage with atomic write.

func (*JSONPluginStateStore) SetConfig

func (s *JSONPluginStateStore) SetConfig(ctx context.Context, name string, config map[string]any) error

SetConfig stores configuration for a plugin.

func (*JSONPluginStateStore) SetEnabled

func (s *JSONPluginStateStore) SetEnabled(ctx context.Context, name string, enabled bool) error

SetEnabled enables or disables a plugin by name.

type LoaderError

type LoaderError struct {
	Path    string // plugin directory path
	Op      string // operation (discover, load, validate)
	Message string // error message
	Cause   error  // underlying error
}

LoaderError represents an error during plugin loading operations.

func NewLoaderError

func NewLoaderError(op, path, message string) *LoaderError

NewLoaderError creates a new LoaderError.

func WrapLoaderError

func WrapLoaderError(op, path string, cause error) *LoaderError

WrapLoaderError wraps an existing error as a LoaderError.

func (*LoaderError) Error

func (e *LoaderError) Error() string

Error implements the error interface.

func (*LoaderError) Unwrap

func (e *LoaderError) Unwrap() error

Unwrap returns the underlying error.

type ManifestParseError

type ManifestParseError struct {
	File    string // file path
	Field   string // field path (e.g., "config.webhook_url")
	Message string // error message
	Cause   error  // underlying error
}

ManifestParseError represents an error during plugin manifest parsing.

func NewManifestParseError

func NewManifestParseError(file, field, message string) *ManifestParseError

NewManifestParseError creates a new ManifestParseError with field and message.

func WrapManifestParseError

func WrapManifestParseError(file string, cause error) *ManifestParseError

WrapManifestParseError wraps an existing error as a ManifestParseError.

func (*ManifestParseError) Error

func (e *ManifestParseError) Error() string

Error implements the error interface.

func (*ManifestParseError) Unwrap

func (e *ManifestParseError) Unwrap() error

Unwrap returns the underlying error.

type ManifestParser

type ManifestParser struct{}

ManifestParser parses plugin manifests from YAML files.

func NewManifestParser

func NewManifestParser() *ManifestParser

NewManifestParser creates a new ManifestParser.

func (*ManifestParser) Parse

Parse reads and parses a plugin manifest from an io.Reader.

func (*ManifestParser) ParseFile

func (p *ManifestParser) ParseFile(path string) (*pluginmodel.Manifest, error)

ParseFile reads and parses a plugin manifest from a file path.

type OperationRegistry

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

OperationRegistry manages registration of plugin-provided operations. Thread-safe for concurrent access.

func NewOperationRegistry

func NewOperationRegistry() *OperationRegistry

NewOperationRegistry creates a new empty operation registry.

func (*OperationRegistry) Clear

func (r *OperationRegistry) Clear()

Clear removes all registered operations. Useful for testing.

func (*OperationRegistry) Count

func (r *OperationRegistry) Count() int

Count returns the total number of registered operations.

func (*OperationRegistry) GetOperation

func (r *OperationRegistry) GetOperation(name string) (*pluginmodel.OperationSchema, bool)

GetOperation returns an operation by name. Returns nil and false if the operation is not found.

func (*OperationRegistry) GetOperationSource

func (r *OperationRegistry) GetOperationSource(operationName string) (string, bool)

GetOperationSource returns the plugin name that registered an operation. Returns empty string and false if the operation is not found.

func (*OperationRegistry) GetPluginOperations

func (r *OperationRegistry) GetPluginOperations(pluginName string) []*pluginmodel.OperationSchema

GetPluginOperations returns all operations registered by a specific plugin.

func (*OperationRegistry) Operations

func (r *OperationRegistry) Operations() []*pluginmodel.OperationSchema

Operations returns all registered operations as a slice. Returns an empty slice if no operations are registered.

func (*OperationRegistry) RegisterOperation

func (r *OperationRegistry) RegisterOperation(op *pluginmodel.OperationSchema) error

RegisterOperation adds a plugin operation to the registry. Returns ErrOperationAlreadyRegistered if an operation with the same name exists. Returns ErrInvalidOperation if the operation schema is nil or has no name.

func (*OperationRegistry) UnregisterOperation

func (r *OperationRegistry) UnregisterOperation(name string) error

UnregisterOperation removes a plugin operation from the registry. Returns ErrOperationNotFound if the operation is not registered.

func (*OperationRegistry) UnregisterPluginOperations

func (r *OperationRegistry) UnregisterPluginOperations(pluginName string) error

UnregisterPluginOperations removes all operations provided by a specific plugin. Useful when unloading or disabling a plugin.

type RPCManagerError

type RPCManagerError struct {
	Op      string // operation (load, init, shutdown)
	Plugin  string // plugin name
	Message string // error message
	Cause   error  // underlying error
}

RPCManagerError represents an error during plugin lifecycle operations.

func NewRPCManagerError

func NewRPCManagerError(op, pluginName, message string) *RPCManagerError

NewRPCManagerError creates a new RPCManagerError.

func WrapRPCManagerError

func WrapRPCManagerError(op, pluginName string, cause error) *RPCManagerError

WrapRPCManagerError wraps an existing error as an RPCManagerError.

func (*RPCManagerError) Error

func (e *RPCManagerError) Error() string

Error implements the error interface.

func (*RPCManagerError) Unwrap

func (e *RPCManagerError) Unwrap() error

Unwrap returns the underlying error.

type RPCPluginManager

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

RPCPluginManager implements PluginManager using HashiCorp go-plugin for RPC. It manages plugin lifecycle: discovery, loading, initialization, and shutdown.

func NewRPCPluginManager

func NewRPCPluginManager(loader *FileSystemLoader) *RPCPluginManager

NewRPCPluginManager creates a new RPCPluginManager.

func (*RPCPluginManager) Discover

Discover finds plugins in the plugins directory. Returns ErrNoPluginsConfigured if no loader or plugins directory is configured.

func (*RPCPluginManager) Execute

func (m *RPCPluginManager) Execute(ctx context.Context, name string, inputs map[string]any) (*pluginmodel.OperationResult, error)

Execute delegates an operation call to the correct connected plugin via gRPC. Name format is "pluginName.operationName" (consistent with built-in providers). If unprefixed, iterates all connections as fallback.

func (*RPCPluginManager) Get

Get returns plugin info by name. Returns (nil, false) if plugin not found.

func (*RPCPluginManager) GetOperation

func (m *RPCPluginManager) GetOperation(name string) (*pluginmodel.OperationSchema, bool)

GetOperation returns an operation schema by name, searching all connected plugins. Name format is "pluginName.operationName" (consistent with built-in providers). Uses an internal 5s timeout per call because the port interface does not accept ctx.

func (*RPCPluginManager) Init

func (m *RPCPluginManager) Init(ctx context.Context, name string, config map[string]any) error

Init initializes a loaded plugin with configuration.

func (*RPCPluginManager) List

List returns all known plugins.

func (*RPCPluginManager) ListOperations

func (m *RPCPluginManager) ListOperations() []*pluginmodel.OperationSchema

ListOperations returns all operation schemas from all connected plugins. Calls gRPC ListOperations on each connection; skips plugins that fail. Uses an internal 5s timeout per call because the port interface does not accept ctx.

func (*RPCPluginManager) Load

func (m *RPCPluginManager) Load(ctx context.Context, name string) error

Load loads a plugin by name. The plugin must have been discovered first, or a pluginsDir must be configured.

func (*RPCPluginManager) SetPluginsDir

func (m *RPCPluginManager) SetPluginsDir(dir string)

SetPluginsDir sets the directory to discover plugins from.

func (*RPCPluginManager) Shutdown

func (m *RPCPluginManager) Shutdown(ctx context.Context, name string) error

Shutdown stops a running plugin gracefully. Full implementation: gRPC Shutdown call, client.Kill(), connection cleanup from m.connections.

func (*RPCPluginManager) ShutdownAll

func (m *RPCPluginManager) ShutdownAll(ctx context.Context) error

ShutdownAll stops all running plugins with a 5s per-plugin deadline. Errors are accumulated via errors.Join() so all plugins are attempted even on partial failure.

type Version

type Version struct {
	Major      int    // Major version number
	Minor      int    // Minor version number
	Patch      int    // Patch version number
	Prerelease string // Prerelease identifier (e.g., "alpha.1")
}

Version represents a parsed semantic version.

func ParseVersion

func ParseVersion(s string) (Version, error)

ParseVersion parses a version string into a Version struct. Accepts formats: "1.0.0", "1.0.0-alpha.1"

func (Version) Compare

func (v Version) Compare(other Version) int

Compare compares this version to another. Returns -1 if v < other, 0 if v == other, 1 if v > other.

func (Version) String

func (v Version) String() string

String returns the string representation of the version.

Jump to

Keyboard shortcuts

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