Documentation
¶
Overview ¶
Package external provides gRPC-based external plugin support for the workflow engine. External plugins run as separate processes communicating over gRPC via hashicorp/go-plugin.
Index ¶
- Constants
- Variables
- func AsModuleError(m modular.Module) error
- func NewErrorModule(name string, err error) modular.Module
- type CallbackServer
- func (s *CallbackServer) GetService(_ context.Context, req *pb.GetServiceRequest) (*pb.GetServiceResponse, error)
- func (s *CallbackServer) Log(_ context.Context, req *pb.LogRequest) (*emptypb.Empty, error)
- func (s *CallbackServer) PublishMessage(_ context.Context, req *pb.PublishMessageRequest) (*pb.PublishMessageResponse, error)
- func (s *CallbackServer) SetMessagePublishFunc(fn MessagePublishFunc)
- func (s *CallbackServer) SetMessageSubscribeFunc(fn MessageSubscribeFunc)
- func (s *CallbackServer) Subscribe(_ context.Context, req *pb.SubscribeRequest) (*pb.ErrorResponse, error)
- func (s *CallbackServer) TriggerWorkflow(_ context.Context, req *pb.TriggerWorkflowRequest) (*pb.ErrorResponse, error)
- func (s *CallbackServer) Unsubscribe(_ context.Context, req *pb.UnsubscribeRequest) (*pb.ErrorResponse, error)
- type ExternalPluginAdapter
- func (a *ExternalPluginAdapter) Capabilities() []capability.Contract
- func (a *ExternalPluginAdapter) ConfigFragmentBytes() []byte
- func (a *ExternalPluginAdapter) ConfigTransformHooks() []plugin.ConfigTransformHook
- func (a *ExternalPluginAdapter) Conn() *grpc.ClientConn
- func (a *ExternalPluginAdapter) ContractRegistry() *pb.ContractRegistry
- func (a *ExternalPluginAdapter) ContractRegistryError() error
- func (a *ExternalPluginAdapter) Dependencies() []plugin.PluginDependency
- func (a *ExternalPluginAdapter) DeployTargets() map[string]deploy.DeployTarget
- func (a *ExternalPluginAdapter) Description() string
- func (a *ExternalPluginAdapter) EngineManifest() *plugin.PluginManifest
- func (a *ExternalPluginAdapter) GetAsset(path string) ([]byte, string, error)
- func (a *ExternalPluginAdapter) IaCStateBackendClients() (map[string]pb.IaCStateBackendClient, error)
- func (a *ExternalPluginAdapter) IsConfigMutable() bool
- func (a *ExternalPluginAdapter) IsSamplePlugin() bool
- func (a *ExternalPluginAdapter) KubernetesBackendClients() (map[string]pb.ResourceDriverClient, error)
- func (a *ExternalPluginAdapter) ModuleFactories() map[string]plugin.ModuleFactory
- func (a *ExternalPluginAdapter) ModuleSchemas() []*schema.ModuleSchema
- func (a *ExternalPluginAdapter) Name() string
- func (a *ExternalPluginAdapter) OnDisable(_ plugin.PluginContext) error
- func (a *ExternalPluginAdapter) OnEnable(_ plugin.PluginContext) error
- func (a *ExternalPluginAdapter) RegisterRoutes(_ *http.ServeMux)
- func (a *ExternalPluginAdapter) SampleCategory() string
- func (a *ExternalPluginAdapter) SidecarProviders() map[string]deploy.SidecarProvider
- func (a *ExternalPluginAdapter) StepFactories() map[string]plugin.StepFactory
- func (a *ExternalPluginAdapter) StepSchemas() []*schema.StepSchema
- func (a *ExternalPluginAdapter) TriggerFactories() map[string]plugin.TriggerFactory
- func (a *ExternalPluginAdapter) UIPages() []plugin.UIPageDef
- func (a *ExternalPluginAdapter) Version() string
- func (a *ExternalPluginAdapter) WiringHooks() []plugin.WiringHook
- func (a *ExternalPluginAdapter) WorkflowHandlers() map[string]plugin.WorkflowHandlerFactory
- type ExternalPluginManager
- func (m *ExternalPluginManager) DiscoverPlugins() ([]string, error)
- func (m *ExternalPluginManager) IsLoaded(name string) bool
- func (m *ExternalPluginManager) LoadPlugin(name string) (*ExternalPluginAdapter, error)
- func (m *ExternalPluginManager) LoadedPlugins() []string
- func (m *ExternalPluginManager) ReloadPlugin(name string) (*ExternalPluginAdapter, error)
- func (m *ExternalPluginManager) SetCallbackServer(server *CallbackServer)
- func (m *ExternalPluginManager) Shutdown()
- func (m *ExternalPluginManager) UnloadPlugin(name string) error
- type GRPCPlugin
- type MessagePublishFunc
- type MessageSubscribeFunc
- type PluginClient
- type PluginHandler
- type RemoteModule
- func (m *RemoteModule) Dependencies() []string
- func (m *RemoteModule) Destroy() error
- func (m *RemoteModule) Init(app modular.Application) error
- func (m *RemoteModule) InvokeService(method string, args map[string]any) (map[string]any, error)
- func (m *RemoteModule) InvokeServiceContext(ctx context.Context, method string, args map[string]any) (map[string]any, error)
- func (m *RemoteModule) Name() string
- func (m *RemoteModule) ProvidesServices() []string
- func (m *RemoteModule) RegisterConfig(app modular.Application) error
- func (m *RemoteModule) RequiresServices() []string
- func (m *RemoteModule) SetDependencies(deps []string)
- func (m *RemoteModule) Start(ctx context.Context) error
- func (m *RemoteModule) Stop(ctx context.Context) error
- type RemoteStep
- type RemoteTrigger
- func (t *RemoteTrigger) Configure(_ modular.Application, triggerConfig any) error
- func (t *RemoteTrigger) Destroy() error
- func (t *RemoteTrigger) Init(_ modular.Application) error
- func (t *RemoteTrigger) Name() string
- func (t *RemoteTrigger) Start(ctx context.Context) error
- func (t *RemoteTrigger) Stop(ctx context.Context) error
- type SecurityScannerRemoteModule
- type ServiceLookupFunc
- type TriggerFunc
- type UIManifest
- type UINavItem
- type UIPluginEntry
- type UIPluginHandler
- type UIPluginInfo
- type UIPluginManager
- func (m *UIPluginManager) AllUIPluginInfos() []UIPluginInfo
- func (m *UIPluginManager) AsNativePlugin(name string) plugin.NativePlugin
- func (m *UIPluginManager) DiscoverPlugins() ([]string, error)
- func (m *UIPluginManager) GetPlugin(name string) (*UIPluginEntry, bool)
- func (m *UIPluginManager) IsLoaded(name string) bool
- func (m *UIPluginManager) LoadPlugin(name string) error
- func (m *UIPluginManager) LoadedPlugins() []string
- func (m *UIPluginManager) ReloadPlugin(name string) error
- func (m *UIPluginManager) ServeAssets(name string) http.Handler
- func (m *UIPluginManager) UIPages(name string) []plugin.UIPageDef
- func (m *UIPluginManager) UnloadPlugin(name string) error
- type UIPluginNativePlugin
- func (p *UIPluginNativePlugin) Dependencies() []plugin.PluginDependency
- func (p *UIPluginNativePlugin) Description() string
- func (p *UIPluginNativePlugin) Name() string
- func (p *UIPluginNativePlugin) OnDisable(_ plugin.PluginContext) error
- func (p *UIPluginNativePlugin) OnEnable(_ plugin.PluginContext) error
- func (p *UIPluginNativePlugin) RegisterRoutes(_ *http.ServeMux)
- func (p *UIPluginNativePlugin) UIPages() []plugin.UIPageDef
- func (p *UIPluginNativePlugin) Version() string
Constants ¶
const ( // ProtocolVersion is the plugin protocol version. // Increment this when making breaking changes to the gRPC interface. ProtocolVersion = 1 // MagicCookieKey is the environment variable used for the handshake. MagicCookieKey = "WORKFLOW_PLUGIN" // MagicCookieValue is the expected value for the handshake cookie. MagicCookieValue = "workflow-external-plugin-v1" )
Variables ¶
var Handshake = goplugin.HandshakeConfig{ ProtocolVersion: ProtocolVersion, MagicCookieKey: MagicCookieKey, MagicCookieValue: MagicCookieValue, }
Handshake is the shared handshake configuration between host and plugins. Both the host (client) and plugin (server) must use identical values.
Functions ¶
func AsModuleError ¶ added in v0.20.3
AsModuleError returns the wrapped error if m was produced by a failed CreateModule call (i.e. the factory returned an *errorModule), or nil if m is a successfully-created module. Callers outside this package use this to surface plugin-reported errors without depending on the unexported type.
func NewErrorModule ¶ added in v0.20.3
NewErrorModule returns a Module that surfaces err from Init and Start. Exported for use in tests that need to simulate a plugin factory failure without importing the unexported errorModule type directly.
Types ¶
type CallbackServer ¶
type CallbackServer struct {
pb.UnimplementedEngineCallbackServiceServer
// contains filtered or unexported fields
}
CallbackServer implements the EngineCallbackService gRPC server. It runs on the host and is called by plugin processes.
func NewCallbackServer ¶
func NewCallbackServer(onTrigger TriggerFunc, lookup ServiceLookupFunc, logger *log.Logger) *CallbackServer
NewCallbackServer creates a new callback server.
func (*CallbackServer) GetService ¶
func (s *CallbackServer) GetService(_ context.Context, req *pb.GetServiceRequest) (*pb.GetServiceResponse, error)
func (*CallbackServer) Log ¶
func (s *CallbackServer) Log(_ context.Context, req *pb.LogRequest) (*emptypb.Empty, error)
func (*CallbackServer) PublishMessage ¶ added in v0.1.5
func (s *CallbackServer) PublishMessage(_ context.Context, req *pb.PublishMessageRequest) (*pb.PublishMessageResponse, error)
func (*CallbackServer) SetMessagePublishFunc ¶ added in v0.1.5
func (s *CallbackServer) SetMessagePublishFunc(fn MessagePublishFunc)
SetMessagePublishFunc configures the callback for message publishing.
func (*CallbackServer) SetMessageSubscribeFunc ¶ added in v0.1.5
func (s *CallbackServer) SetMessageSubscribeFunc(fn MessageSubscribeFunc)
SetMessageSubscribeFunc configures the callback for message subscriptions.
func (*CallbackServer) Subscribe ¶ added in v0.1.5
func (s *CallbackServer) Subscribe(_ context.Context, req *pb.SubscribeRequest) (*pb.ErrorResponse, error)
func (*CallbackServer) TriggerWorkflow ¶
func (s *CallbackServer) TriggerWorkflow(_ context.Context, req *pb.TriggerWorkflowRequest) (*pb.ErrorResponse, error)
func (*CallbackServer) Unsubscribe ¶ added in v0.1.5
func (s *CallbackServer) Unsubscribe(_ context.Context, req *pb.UnsubscribeRequest) (*pb.ErrorResponse, error)
type ExternalPluginAdapter ¶
type ExternalPluginAdapter struct {
// contains filtered or unexported fields
}
ExternalPluginAdapter wraps a gRPC plugin client to implement plugin.EnginePlugin. The engine sees this as a regular plugin — no changes to engine.go needed.
func NewExternalPluginAdapter ¶
func NewExternalPluginAdapter(name string, client *PluginClient, diskManifest *plugin.PluginManifest) (*ExternalPluginAdapter, error)
NewExternalPluginAdapter creates an adapter from a connected plugin client. diskManifest is the *plugin.PluginManifest loaded by the manager at manager.go:108 via pluginpkg.LoadManifest + Validate. It is used as the canonical fallback when the plugin's gRPC GetManifest RPC returns codes.Unimplemented (strict-cutover IaC plugins) or an empty Version (defensive). Pass nil only in tests that exercise the no-disk fallback path; production callers must pass the manager-loaded manifest.
func (*ExternalPluginAdapter) Capabilities ¶
func (a *ExternalPluginAdapter) Capabilities() []capability.Contract
func (*ExternalPluginAdapter) ConfigFragmentBytes ¶ added in v0.3.3
func (a *ExternalPluginAdapter) ConfigFragmentBytes() []byte
ConfigFragmentBytes returns the raw YAML config fragment fetched from the plugin.
func (*ExternalPluginAdapter) ConfigTransformHooks ¶ added in v0.1.7
func (a *ExternalPluginAdapter) ConfigTransformHooks() []plugin.ConfigTransformHook
func (*ExternalPluginAdapter) Conn ¶ added in v0.27.7
func (a *ExternalPluginAdapter) Conn() *grpc.ClientConn
Conn returns the underlying gRPC client connection used to talk to the plugin process. Callers (notably wfctl's typed-IaC cutover in plan Task 16) construct additional typed gRPC service clients against this conn — for example `pb.NewIaCProviderRequiredClient(adapter.Conn())`.
Returns nil in two cases:
- The adapter was constructed without a backing PluginClient (e.g. `newExternalPluginAdapterWithContractRegistry` test fixtures populate manifest + registry directly without a gRPC subprocess).
- The adapter has a non-nil PluginClient but its underlying PluginClient.Conn() is itself nil (in-process test plumbing that wires only the PluginServiceClient interface without a real *grpc.ClientConn).
Callers MUST nil-check before constructing typed clients.
The connection lifecycle is owned by the host's plugin manager — callers MUST NOT call Close() on the returned conn. The plugin shutdown path tears it down via the registered Closer.
func (*ExternalPluginAdapter) ContractRegistry ¶ added in v0.19.0
func (a *ExternalPluginAdapter) ContractRegistry() *pb.ContractRegistry
func (*ExternalPluginAdapter) ContractRegistryError ¶ added in v0.19.0
func (a *ExternalPluginAdapter) ContractRegistryError() error
func (*ExternalPluginAdapter) Dependencies ¶
func (a *ExternalPluginAdapter) Dependencies() []plugin.PluginDependency
func (*ExternalPluginAdapter) DeployTargets ¶ added in v0.3.5
func (a *ExternalPluginAdapter) DeployTargets() map[string]deploy.DeployTarget
func (*ExternalPluginAdapter) Description ¶
func (a *ExternalPluginAdapter) Description() string
func (*ExternalPluginAdapter) EngineManifest ¶
func (a *ExternalPluginAdapter) EngineManifest() *plugin.PluginManifest
func (*ExternalPluginAdapter) GetAsset ¶ added in v0.3.3
func (a *ExternalPluginAdapter) GetAsset(path string) ([]byte, string, error)
GetAsset fetches a static asset from the plugin by path.
func (*ExternalPluginAdapter) IaCStateBackendClients ¶ added in v0.51.11
func (a *ExternalPluginAdapter) IaCStateBackendClients() (map[string]pb.IaCStateBackendClient, error)
IaCStateBackendClients implements plugin.IaCStateBackendProvider. At plugin-load the engine type-asserts the adapter against that interface and registers each returned (name → client) pair into module's iac.state backend registry. Amendment A2 (decisions/0035).
Behaviour:
- If the plugin's ContractRegistry does not advertise the IaCStateBackend service: when the disk manifest declares a non-empty IaCStateBackends list, that is a silent misconfiguration (the plugin claims backends but the host would register none) — return an error so plugin-load fails loudly. When the manifest is also silent, the plugin genuinely serves no state backend — return (nil, nil); the engine type-assert still succeeds and just registers nothing.
- Otherwise call the live ListBackendNames RPC for the authoritative backend-name list and cross-check it against the plugin's declared PluginManifest.IaCStateBackends.
Cross-check decision: the RPC is the live source of truth. The manifest is only consulted as a declared-vs-served consistency guard — when the manifest declares a non-empty backend set, it MUST match the RPC result exactly (a plugin whose live RPC contradicts its declared manifest is misconfigured and is rejected). When the manifest is silent (no diskManifest, or an empty IaCStateBackends list — e.g. a strict-cutover plugin that left GetManifest unimplemented and whose plugin.json omits the field) the RPC result is accepted on its own.
func (*ExternalPluginAdapter) IsConfigMutable ¶ added in v0.3.3
func (a *ExternalPluginAdapter) IsConfigMutable() bool
IsConfigMutable returns true if tenants can override the plugin's config fragment.
func (*ExternalPluginAdapter) IsSamplePlugin ¶ added in v0.3.3
func (a *ExternalPluginAdapter) IsSamplePlugin() bool
IsSamplePlugin returns true if the plugin declares a sample category.
func (*ExternalPluginAdapter) KubernetesBackendClients ¶ added in v0.53.0
func (a *ExternalPluginAdapter) KubernetesBackendClients() (map[string]pb.ResourceDriverClient, error)
KubernetesBackendClients implements plugin.KubernetesBackendProvider. At plugin-load the engine type-asserts the adapter against that interface and registers each returned (cluster-type → ResourceDriver client) pair into module's kubernetes backend registry. Per ADR 0037.
Behaviour:
- If the plugin does not advertise the ResourceDriver service it serves no kubernetes backend — return (nil, nil); the engine type-assert still succeeds and just registers nothing.
- Otherwise the live Capabilities RPC is the source of truth (mirroring how IaCStateBackendClients trusts the ListBackendNames RPC): when it declares the infra.k8s_cluster resource type, the plugin serves the `gke` kubernetes backend and a ResourceDriver client is registered under that name.
func (*ExternalPluginAdapter) ModuleFactories ¶
func (a *ExternalPluginAdapter) ModuleFactories() map[string]plugin.ModuleFactory
func (*ExternalPluginAdapter) ModuleSchemas ¶
func (a *ExternalPluginAdapter) ModuleSchemas() []*schema.ModuleSchema
func (*ExternalPluginAdapter) Name ¶
func (a *ExternalPluginAdapter) Name() string
func (*ExternalPluginAdapter) OnDisable ¶
func (a *ExternalPluginAdapter) OnDisable(_ plugin.PluginContext) error
func (*ExternalPluginAdapter) OnEnable ¶
func (a *ExternalPluginAdapter) OnEnable(_ plugin.PluginContext) error
func (*ExternalPluginAdapter) RegisterRoutes ¶
func (a *ExternalPluginAdapter) RegisterRoutes(_ *http.ServeMux)
func (*ExternalPluginAdapter) SampleCategory ¶ added in v0.3.3
func (a *ExternalPluginAdapter) SampleCategory() string
SampleCategory returns the sample category declared by the plugin.
func (*ExternalPluginAdapter) SidecarProviders ¶ added in v0.3.5
func (a *ExternalPluginAdapter) SidecarProviders() map[string]deploy.SidecarProvider
func (*ExternalPluginAdapter) StepFactories ¶
func (a *ExternalPluginAdapter) StepFactories() map[string]plugin.StepFactory
func (*ExternalPluginAdapter) StepSchemas ¶ added in v0.3.18
func (a *ExternalPluginAdapter) StepSchemas() []*schema.StepSchema
func (*ExternalPluginAdapter) TriggerFactories ¶
func (a *ExternalPluginAdapter) TriggerFactories() map[string]plugin.TriggerFactory
func (*ExternalPluginAdapter) UIPages ¶
func (a *ExternalPluginAdapter) UIPages() []plugin.UIPageDef
func (*ExternalPluginAdapter) Version ¶
func (a *ExternalPluginAdapter) Version() string
func (*ExternalPluginAdapter) WiringHooks ¶
func (a *ExternalPluginAdapter) WiringHooks() []plugin.WiringHook
func (*ExternalPluginAdapter) WorkflowHandlers ¶
func (a *ExternalPluginAdapter) WorkflowHandlers() map[string]plugin.WorkflowHandlerFactory
type ExternalPluginManager ¶
type ExternalPluginManager struct {
// contains filtered or unexported fields
}
ExternalPluginManager discovers, loads, and manages external plugin subprocesses. Each plugin lives in its own subdirectory under the plugins directory and communicates with the host via gRPC through the go-plugin framework.
func NewExternalPluginManager ¶
func NewExternalPluginManager(pluginsDir string, logger *log.Logger) *ExternalPluginManager
NewExternalPluginManager creates a new manager that scans the given directory for plugins.
func (*ExternalPluginManager) DiscoverPlugins ¶
func (m *ExternalPluginManager) DiscoverPlugins() ([]string, error)
DiscoverPlugins scans the plugins directory for subdirectories that contain a plugin.json manifest and an executable binary matching the directory name. It returns the list of discovered plugin names.
func (*ExternalPluginManager) IsLoaded ¶
func (m *ExternalPluginManager) IsLoaded(name string) bool
IsLoaded returns true if the named plugin is currently loaded.
func (*ExternalPluginManager) LoadPlugin ¶
func (m *ExternalPluginManager) LoadPlugin(name string) (*ExternalPluginAdapter, error)
LoadPlugin starts the named plugin subprocess, performs the handshake, and creates an ExternalPluginAdapter. The plugin must have been previously discovered via DiscoverPlugins.
func (*ExternalPluginManager) LoadedPlugins ¶
func (m *ExternalPluginManager) LoadedPlugins() []string
LoadedPlugins returns the names of all currently loaded plugins.
func (*ExternalPluginManager) ReloadPlugin ¶
func (m *ExternalPluginManager) ReloadPlugin(name string) (*ExternalPluginAdapter, error)
ReloadPlugin starts and validates the replacement before stopping the currently loaded plugin. Candidate failure leaves the old process registered.
func (*ExternalPluginManager) SetCallbackServer ¶ added in v0.27.3
func (m *ExternalPluginManager) SetCallbackServer(server *CallbackServer)
SetCallbackServer configures the host callback server used by plugins that expose triggers or host callback features.
func (*ExternalPluginManager) Shutdown ¶
func (m *ExternalPluginManager) Shutdown()
Shutdown kills all loaded plugin subprocesses.
func (*ExternalPluginManager) UnloadPlugin ¶
func (m *ExternalPluginManager) UnloadPlugin(name string) error
UnloadPlugin stops the named plugin subprocess and removes it from the internal map.
type GRPCPlugin ¶
type GRPCPlugin struct {
goplugin.Plugin
// CallbackServer is the host-side callback implementation.
// When non-nil, it will be registered on the broker for plugin access.
CallbackServer *CallbackServer
}
GRPCPlugin implements go-plugin's Plugin and GRPCPlugin interfaces. It bridges between go-plugin's plugin system and our gRPC services.
func (*GRPCPlugin) GRPCClient ¶
func (p *GRPCPlugin) GRPCClient(_ context.Context, broker *goplugin.GRPCBroker, c *grpc.ClientConn) (any, error)
GRPCClient returns the client wrapper (host side). This is called by the host process to get a client that talks to the plugin.
func (*GRPCPlugin) GRPCServer ¶
func (p *GRPCPlugin) GRPCServer(broker *goplugin.GRPCBroker, s *grpc.Server) error
GRPCServer registers the plugin service on the gRPC server (plugin side). This is called by the plugin process.
type MessagePublishFunc ¶ added in v0.1.5
type MessagePublishFunc func(brokerName, topic string, payload []byte, metadata map[string]string) (messageID string, err error)
MessagePublishFunc publishes a message to a named broker topic on behalf of a plugin.
type MessageSubscribeFunc ¶ added in v0.1.5
type MessageSubscribeFunc func(brokerName, topic string, handler func([]byte, map[string]string) error) (cancel func(), err error)
MessageSubscribeFunc subscribes to a topic on a named broker on behalf of a plugin. It returns a cancel function to remove the subscription and any error.
type PluginClient ¶
type PluginClient struct {
// contains filtered or unexported fields
}
PluginClient wraps the gRPC client for the plugin service.
The underlying *grpc.ClientConn is retained so callers that need to instantiate additional typed gRPC clients (e.g. the typed pb.IaCProviderRequiredClient that wfctl's typedIaCAdapter wraps in the strict-contracts cutover, plan Task 16) can do so without going through the legacy pb.PluginServiceClient string-dispatch path. Exposed via Conn() rather than as a public field so the rest of the PluginClient surface stays opaque.
func (*PluginClient) Conn ¶ added in v0.27.7
func (p *PluginClient) Conn() *grpc.ClientConn
Conn returns the underlying gRPC client connection to the plugin process. Callers MAY use it to construct additional typed gRPC service clients (for example pb.NewIaCProviderRequiredClient).
The connection lifecycle is owned by the host's plugin manager — callers MUST NOT call Close() on it. The connection is shared across every typed-client constructed against it; closing it would tear down every other consumer too.
type PluginHandler ¶
type PluginHandler struct {
// contains filtered or unexported fields
}
PluginHandler provides HTTP API endpoints for managing external plugins.
func NewPluginHandler ¶
func NewPluginHandler(manager *ExternalPluginManager) *PluginHandler
NewPluginHandler creates a new handler backed by the given external plugin manager.
func (*PluginHandler) RegisterRoutes ¶
func (h *PluginHandler) RegisterRoutes(mux *http.ServeMux)
RegisterRoutes registers the external plugin management HTTP routes on the given mux.
type RemoteModule ¶
type RemoteModule struct {
// contains filtered or unexported fields
}
RemoteModule implements modular.Module by delegating to a gRPC plugin.
func NewRemoteModule ¶
func NewRemoteModule(name, handleID string, client pb.PluginServiceClient, contracts ...remoteModuleContracts) *RemoteModule
NewRemoteModule creates a remote module proxy.
func (*RemoteModule) Dependencies ¶
func (m *RemoteModule) Dependencies() []string
func (*RemoteModule) Destroy ¶
func (m *RemoteModule) Destroy() error
Destroy releases the remote module resources.
func (*RemoteModule) Init ¶
func (m *RemoteModule) Init(app modular.Application) error
func (*RemoteModule) InvokeService ¶
InvokeService calls a named method on the remote module's service interface.
func (*RemoteModule) InvokeServiceContext ¶ added in v0.19.0
func (m *RemoteModule) InvokeServiceContext(ctx context.Context, method string, args map[string]any) (map[string]any, error)
InvokeServiceContext calls a named method on the remote module's service interface using the caller's context.
func (*RemoteModule) Name ¶
func (m *RemoteModule) Name() string
func (*RemoteModule) ProvidesServices ¶
func (m *RemoteModule) ProvidesServices() []string
func (*RemoteModule) RegisterConfig ¶
func (m *RemoteModule) RegisterConfig(app modular.Application) error
func (*RemoteModule) RequiresServices ¶
func (m *RemoteModule) RequiresServices() []string
func (*RemoteModule) SetDependencies ¶ added in v0.51.9
func (m *RemoteModule) SetDependencies(deps []string)
SetDependencies records the yaml-level `dependsOn:` keys declared for this module so modular's Init() walker can honour them. Called by the engine from BuildFromConfig immediately after the factory returns and before app.RegisterModule, but only when the module's `modCfg.DependsOn` is **non-empty after filtering** (filterResolvableDeps drops empty strings + names not present in cfg.Modules) AND the module satisfies `interface{ SetDependencies([]string) }` — modules with no resolvable dependsOn are skipped so a constructor-time default isn't clobbered with a SetDependencies(nil) call. See workflow#663.
Defensive copy: although the engine already copies before calling, the setter is exported and Dependencies() exposes the same backing array to modular. Copying here too means any caller (engine, tests, future integration paths) can mutate its source slice after calling without silently corrupting this module's init graph.
type RemoteStep ¶
type RemoteStep struct {
// contains filtered or unexported fields
}
RemoteStep implements module.PipelineStep by delegating to a gRPC plugin.
func NewRemoteStep ¶
func NewRemoteStep(name, handleID string, client pb.PluginServiceClient, config map[string]any, contracts ...*pb.ContractDescriptor) *RemoteStep
NewRemoteStep creates a remote step proxy. config holds the raw (possibly template-containing) step configuration that will be resolved against the live pipeline context on each Execute call.
func NewRemoteStepWithContractTypes ¶ added in v0.19.0
func NewRemoteStepWithContractTypes(name, handleID string, client pb.PluginServiceClient, config map[string]any, contract *pb.ContractDescriptor, types protoregistry.MessageTypeResolver) *RemoteStep
func (*RemoteStep) Destroy ¶
func (s *RemoteStep) Destroy() error
Destroy releases the remote step resources.
func (*RemoteStep) Execute ¶
func (s *RemoteStep) Execute(ctx context.Context, pc *module.PipelineContext) (*module.StepResult, error)
func (*RemoteStep) Name ¶
func (s *RemoteStep) Name() string
type RemoteTrigger ¶ added in v0.1.5
type RemoteTrigger struct {
// contains filtered or unexported fields
}
RemoteTrigger implements module.Trigger by proxying to a plugin trigger type. Trigger lifecycle (Start/Stop) is managed through the plugin's module RPCs, treating trigger handles as module handles.
func NewRemoteTrigger ¶ added in v0.1.5
func NewRemoteTrigger(typeName, name string, client pb.PluginServiceClient) *RemoteTrigger
NewRemoteTrigger creates a remote trigger proxy. The plugin handle is allocated after Configure receives YAML trigger config.
func (*RemoteTrigger) Configure ¶ added in v0.1.5
func (t *RemoteTrigger) Configure(_ modular.Application, triggerConfig any) error
Configure applies YAML trigger config and creates the remote trigger handle.
func (*RemoteTrigger) Destroy ¶ added in v0.1.5
func (t *RemoteTrigger) Destroy() error
Destroy releases the remote trigger resources in the plugin process.
func (*RemoteTrigger) Init ¶ added in v0.1.5
func (t *RemoteTrigger) Init(_ modular.Application) error
func (*RemoteTrigger) Name ¶ added in v0.1.5
func (t *RemoteTrigger) Name() string
type SecurityScannerRemoteModule ¶ added in v0.3.23
type SecurityScannerRemoteModule struct {
*RemoteModule
}
SecurityScannerRemoteModule wraps a RemoteModule for security.scanner type modules. On Init it registers a RemoteSecurityScannerProvider in the service registry so that scan steps can call app.GetService("security-scanner", &provider).
func NewSecurityScannerRemoteModule ¶ added in v0.3.23
func NewSecurityScannerRemoteModule(remote *RemoteModule) *SecurityScannerRemoteModule
NewSecurityScannerRemoteModule wraps a RemoteModule as a security scanner module.
func (*SecurityScannerRemoteModule) Init ¶ added in v0.3.23
func (m *SecurityScannerRemoteModule) Init(app modular.Application) error
Init calls the remote Init and registers the scanner provider in the service registry.
type ServiceLookupFunc ¶
ServiceLookupFunc checks if a named service exists in the host.
type TriggerFunc ¶
TriggerFunc is called when a plugin fires a workflow trigger.
type UIManifest ¶ added in v0.1.1
type UIManifest struct {
// Name is the plugin identifier. Must match the plugin directory name.
Name string `json:"name"`
// Version is the plugin version string (e.g. "1.0.0").
Version string `json:"version"`
// Description is a short human-readable description of the plugin.
Description string `json:"description,omitempty"`
NavItems []UINavItem `json:"navItems,omitempty"`
// AssetDir is the subdirectory within the plugin directory that holds
// static assets. Defaults to "assets" when empty.
AssetDir string `json:"assetDir,omitempty"`
}
UIManifest describes the UI contribution of a go-plugin UI plugin. Place this as "ui.json" in the plugin directory alongside "plugin.json".
Directory Layout ¶
plugins/
my-ui-plugin/
my-ui-plugin (binary, required for API handlers; optional for asset-only plugins)
plugin.json (gRPC plugin manifest; required when binary is present)
ui.json (UI manifest: nav items and asset location)
assets/ (static files: HTML, CSS, JS, images, etc.)
index.html
main.js
Asset Versioning ¶
Include a version hash in asset filenames (e.g. main.abc123.js) and reference them from index.html so browsers pick up new files after hot-deploy.
Hot-Reload ¶
After updating assets or ui.json, call:
POST /api/v1/plugins/ui/{name}/reload
This re-reads the manifest and serves the new files without restarting the workflow engine.
Hot-Deploy ¶
Replace the plugin binary and/or assets directory with the new version, then call the reload endpoint above.
type UINavItem ¶ added in v0.1.1
type UINavItem struct {
ID string `json:"id"`
Label string `json:"label"`
Icon string `json:"icon,omitempty"`
// "global" – always visible top-level entries
// "workflow" – shown only when a workflow is open
// "plugin" – plugin-contributed entries (default)
// "tools" – administrative tooling entries
Category string `json:"category,omitempty"`
Order int `json:"order,omitempty"`
// (e.g. "viewer", "editor", "admin", "operator").
RequiredRole string `json:"requiredRole,omitempty"`
// (e.g. "plugins.manage").
RequiredPermission string `json:"requiredPermission,omitempty"`
}
UINavItem describes a single entry in the admin UI navigation sidebar.
type UIPluginEntry ¶ added in v0.1.1
type UIPluginEntry struct {
// Manifest is the parsed ui.json for this plugin.
Manifest UIManifest
// AssetsDir is the absolute path to the plugin's static assets directory.
AssetsDir string
}
UIPluginEntry holds the runtime state of a loaded UI plugin.
type UIPluginHandler ¶ added in v0.1.1
type UIPluginHandler struct {
// contains filtered or unexported fields
}
UIPluginHandler provides HTTP API endpoints for managing UI plugins.
Routes registered by RegisterRoutes:
GET /api/v1/plugins/ui – list loaded UI plugins
GET /api/v1/plugins/ui/available – list all discovered UI plugins
GET /api/v1/plugins/ui/{name}/manifest – get a plugin's UI manifest
POST /api/v1/plugins/ui/{name}/load – load a UI plugin
POST /api/v1/plugins/ui/{name}/unload – unload a UI plugin
POST /api/v1/plugins/ui/{name}/reload – hot-reload a UI plugin
GET /api/v1/plugins/ui/{name}/assets/{path…} – serve static assets
func NewUIPluginHandler ¶ added in v0.1.1
func NewUIPluginHandler(manager *UIPluginManager) *UIPluginHandler
NewUIPluginHandler creates a new handler backed by the given UIPluginManager.
func (*UIPluginHandler) RegisterRoutes ¶ added in v0.1.1
func (h *UIPluginHandler) RegisterRoutes(mux *http.ServeMux)
RegisterRoutes registers all UI plugin HTTP routes on mux.
type UIPluginInfo ¶ added in v0.1.1
type UIPluginInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description,omitempty"`
Loaded bool `json:"loaded"`
}
UIPluginInfo is the JSON representation of a UI plugin for API responses.
type UIPluginManager ¶ added in v0.1.1
type UIPluginManager struct {
// contains filtered or unexported fields
}
UIPluginManager discovers and manages UI plugins under a shared plugins directory. Each UI plugin is a subdirectory that contains a "ui.json" manifest and an optional "assets" subdirectory with static files.
Hot-reload ¶
Calling ReloadPlugin re-reads the manifest and the assets directory from disk without restarting the workflow engine. The static file server for the plugin is updated atomically so in-flight requests are not interrupted.
Integration with PluginManager navigation ¶
Call UIPages to get UIPageDef entries for a loaded UI plugin, then register a UIPluginNativePlugin wrapper with a PluginManager to surface those entries through the standard navigation API.
func NewUIPluginManager ¶ added in v0.1.1
func NewUIPluginManager(pluginsDir string, logger *log.Logger) *UIPluginManager
NewUIPluginManager creates a manager that scans the given directory for UI plugins (subdirectories containing a "ui.json" manifest).
func (*UIPluginManager) AllUIPluginInfos ¶ added in v0.1.1
func (m *UIPluginManager) AllUIPluginInfos() []UIPluginInfo
AllUIPluginInfos returns summary information for every currently loaded UI plugin.
func (*UIPluginManager) AsNativePlugin ¶ added in v0.1.1
func (m *UIPluginManager) AsNativePlugin(name string) plugin.NativePlugin
AsNativePlugin returns a plugin.NativePlugin implementation that surfaces the named UI plugin's navigation entries through the standard PluginManager API. Returns nil if the plugin is not loaded.
Use this to register a UI plugin's nav items with a PluginManager:
if np := uiMgr.AsNativePlugin("my-ui-plugin"); np != nil {
_ = pluginMgr.Register(np)
_ = pluginMgr.Enable("my-ui-plugin")
}
func (*UIPluginManager) DiscoverPlugins ¶ added in v0.1.1
func (m *UIPluginManager) DiscoverPlugins() ([]string, error)
DiscoverPlugins scans the plugins directory and returns names of all subdirectories that contain a "ui.json" manifest file.
func (*UIPluginManager) GetPlugin ¶ added in v0.1.1
func (m *UIPluginManager) GetPlugin(name string) (*UIPluginEntry, bool)
GetPlugin returns the entry for the named UI plugin. The second return value is false if the plugin is not loaded.
func (*UIPluginManager) IsLoaded ¶ added in v0.1.1
func (m *UIPluginManager) IsLoaded(name string) bool
IsLoaded returns true if the named UI plugin is currently loaded.
func (*UIPluginManager) LoadPlugin ¶ added in v0.1.1
func (m *UIPluginManager) LoadPlugin(name string) error
LoadPlugin reads the "ui.json" manifest for the named plugin and registers it. If the plugin is already loaded it is replaced (hot-reload semantics).
func (*UIPluginManager) LoadedPlugins ¶ added in v0.1.1
func (m *UIPluginManager) LoadedPlugins() []string
LoadedPlugins returns the names of all currently loaded UI plugins.
func (*UIPluginManager) ReloadPlugin ¶ added in v0.1.1
func (m *UIPluginManager) ReloadPlugin(name string) error
ReloadPlugin re-reads the manifest and assets directory from disk for the named plugin. This is the primary hot-reload mechanism: deploy updated assets to the plugin directory, then call this method.
func (*UIPluginManager) ServeAssets ¶ added in v0.1.1
func (m *UIPluginManager) ServeAssets(name string) http.Handler
ServeAssets returns an http.Handler that serves the static assets of the named plugin directly from its assets directory. Returns nil if the plugin is not loaded or its assets directory does not exist.
func (*UIPluginManager) UIPages ¶ added in v0.1.1
func (m *UIPluginManager) UIPages(name string) []plugin.UIPageDef
UIPages converts the nav items declared in a loaded UI plugin's manifest into plugin.UIPageDef entries compatible with the PluginManager navigation system.
func (*UIPluginManager) UnloadPlugin ¶ added in v0.1.1
func (m *UIPluginManager) UnloadPlugin(name string) error
UnloadPlugin removes a UI plugin from the manager. Returns an error if the plugin is not currently loaded.
type UIPluginNativePlugin ¶ added in v0.1.1
type UIPluginNativePlugin struct {
// contains filtered or unexported fields
}
UIPluginNativePlugin adapts a loaded UI plugin as a plugin.NativePlugin so its navigation entries are visible through the standard PluginManager API. It implements a read-through to the UIPluginManager so that hot-reloads automatically update the navigation data returned by UIPages.
func (*UIPluginNativePlugin) Dependencies ¶ added in v0.1.1
func (p *UIPluginNativePlugin) Dependencies() []plugin.PluginDependency
func (*UIPluginNativePlugin) Description ¶ added in v0.1.1
func (p *UIPluginNativePlugin) Description() string
func (*UIPluginNativePlugin) Name ¶ added in v0.1.1
func (p *UIPluginNativePlugin) Name() string
func (*UIPluginNativePlugin) OnDisable ¶ added in v0.1.1
func (p *UIPluginNativePlugin) OnDisable(_ plugin.PluginContext) error
func (*UIPluginNativePlugin) OnEnable ¶ added in v0.1.1
func (p *UIPluginNativePlugin) OnEnable(_ plugin.PluginContext) error
func (*UIPluginNativePlugin) RegisterRoutes ¶ added in v0.1.1
func (p *UIPluginNativePlugin) RegisterRoutes(_ *http.ServeMux)
func (*UIPluginNativePlugin) UIPages ¶ added in v0.1.1
func (p *UIPluginNativePlugin) UIPages() []plugin.UIPageDef
UIPages reads the current nav items from the UIPluginManager so that hot-reloads (which call UIPluginManager.ReloadPlugin) are reflected immediately without re-registering the plugin.
func (*UIPluginNativePlugin) Version ¶ added in v0.1.1
func (p *UIPluginNativePlugin) Version() string