Documentation
¶
Overview ¶
Package sdk provides the plugin author interface and helpers for implementing preflight plugins as standalone executables speaking JSON-RPC over stdin/stdout.
Index ¶
- Constants
- func IsProtocolError(err error) bool
- func Serve(m Module)
- type ApplyResult
- type CheckResult
- type Client
- func NewClientContext(ctx context.Context, executablePath string, info TargetInfo, ops HandleServer) (*Client, error)
- func NewClientForInspection(ctx context.Context, executablePath string) (*Client, error)
- func NewClientFromCmd(cmd *exec.Cmd, info TargetInfo, ops HandleServer) (*Client, error)
- func NewClientStream(r io.Reader, w io.Writer, closeFn func() error, info TargetInfo, ...) (*Client, error)
- type CommandResult
- type DiscoveredPlugin
- type DiscoveryOptions
- type Handle
- type HandleServer
- type InitializeParams
- type InitializeResult
- type Module
- type OutputFunc
- type PluginStatus
- type ProtocolError
- type TargetInfo
Constants ¶
const ProtocolVersion = "1"
ProtocolVersion is the wire-protocol version this host and SDK speak. Plugins must echo it back in their initialize response; a mismatch or absence is a plugin_protocol error (pre-v1 plugins are rejected).
Variables ¶
This section is empty.
Functions ¶
func IsProtocolError ¶
IsProtocolError reports whether err is a *ProtocolError.
func Serve ¶
func Serve(m Module)
Serve runs the JSON-RPC loop for the given module, reading requests from stdin and writing responses to stdout. Call this from your plugin's main().
The host delivers TargetInfo at initialize; the Handle given to Check/Apply exposes it (plus RunCommand/PutFile/GetFile/Output) by calling back over the same stdio channel — both sides act as JSON-RPC client and server.
Types ¶
type ApplyResult ¶
type ApplyResult struct {
Message string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
}
ApplyResult is returned by a module's Apply method.
type CheckResult ¶
type CheckResult struct {
NeedsChange bool `json:"needs_change"`
Message string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
}
CheckResult is returned by a module's Check method.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the runner-side handle for a JSON-RPC plugin peer. It is transport-agnostic: it speaks the wire protocol over the reader/writer pair supplied at construction and delegates cleanup to an optional close function.
Both sides act as client and server: the Client sends initialize/check/apply requests and forwards the plugin's output notifications to an OutputFunc, while simultaneously answering the plugin's handle-op requests (run_command/put_file/get_file) through the bound HandleServer. One outgoing call is in flight at a time (the codec serializes them); incoming handle-op requests are handled concurrently so a plugin's Check can issue a RunCommand while the host's check call is still outstanding.
func NewClientContext ¶
func NewClientContext(ctx context.Context, executablePath string, info TargetInfo, ops HandleServer) (*Client, error)
NewClientContext starts the plugin, performs the v1 initialize handshake (protocol_version + enriched TargetInfo), and binds the plugin's handle ops to ops. Used by the runtime adapter against a real target.
func NewClientForInspection ¶
NewClientForInspection starts a plugin with no target bound, for plugin list/info/staging paths that only read name/version.
func NewClientFromCmd ¶
func NewClientFromCmd(cmd *exec.Cmd, info TargetInfo, ops HandleServer) (*Client, error)
NewClientFromCmd starts the given command and connects a Client to its stdin/stdout for JSON-RPC communication. The command must not have been started yet. info is delivered at initialize; ops answers handle-op requests.
func NewClientStream ¶
func NewClientStream(r io.Reader, w io.Writer, closeFn func() error, info TargetInfo, ops HandleServer) (*Client, error)
NewClientStream connects a Client to a JSON-RPC plugin peer over the given reader/writer pair, performs the initialize handshake (sending protocol_version and the enriched TargetInfo, and requiring the plugin to echo protocol_version back), and binds the plugin's handle-op requests to ops. If closeFn is non-nil it is invoked exactly once from Close (and on initialize failure).
ops carries the target effects the plugin exercises (RunCommand/PutFile/GetFile). For inspection paths with no target, pass NoopHandleServer(). info is the TargetInfo delivered to the plugin at initialize.
func (*Client) Apply ¶
func (c *Client) Apply(ctx context.Context, args map[string]any, out OutputFunc) (ApplyResult, error)
Apply calls the plugin's apply method, forwarding output to out.
func (*Client) Check ¶
func (c *Client) Check(ctx context.Context, args map[string]any, out OutputFunc) (CheckResult, error)
Check calls the plugin's check method, forwarding output to out.
type CommandResult ¶
type CommandResult struct {
Stdout string `json:"stdout"`
Stderr string `json:"stderr"`
ExitCode int `json:"exit_code"`
}
CommandResult is the outcome of a RunCommand handle op: the script runs in the target's native shell and returns separated stdout/stderr and the exit code.
type DiscoveredPlugin ¶
DiscoveredPlugin is one plugin executable found during scanning.
func Scan ¶
func Scan(opts DiscoveryOptions) ([]DiscoveredPlugin, error)
Scan returns every matching plugin executable in scan order. PreferredDirs are searched before the default binary/home/cwd directories.
type DiscoveryOptions ¶
type DiscoveryOptions struct {
BinaryDir string
WorkingDir string
PreferredDirs []string
DisableFallbackDirs bool
}
DiscoveryOptions controls plugin scan order.
type Handle ¶
type Handle interface {
HandleServer
// Info returns the TargetInfo delivered at initialize.
Info() TargetInfo
// Output emits a streaming line back to the host's output channel.
Output(line string)
}
Handle is given to a plugin's Check/Apply. ALL target effects flow through it — including against the local target — so plugins are brought in line with first-party modules. The three target primitives are RunCommand, PutFile/GetFile, and TargetInfo (delivered at initialize and cached). Output carries streaming lines back to the host.
One target op is in flight per session: a plugin that calls RunCommand must wait for its result before issuing another op (or a PutFile/GetFile). For high-latency transports, batch work into a single script-shaped RunCommand rather than many round trips.
File transfer is whole-file in v1: PutFile/GetFile carry the entire payload as a single base64-encoded JSON-RPC frame buffered in memory. Chunked streaming for large files is deferred to v2; keep payloads small (a few MB at most).
type HandleServer ¶
type HandleServer interface {
// RunCommand executes script in the target's native shell (POSIX sh or
// PowerShell per TargetInfo.RuntimeKind) and returns stdout, stderr, and
// the exit code. This is the batching lever for high-latency transports:
// prefer one script that does several things over several ops.
RunCommand(ctx context.Context, script string) (CommandResult, error)
// PutFile writes data to path on the target. File transfer is whole-file
// in v1: the payload is base64-encoded into a single JSON-RPC frame
// buffered in memory; chunked streaming is deferred to v2.
PutFile(ctx context.Context, path string, data []byte) error
// GetFile reads the contents of path from the target (whole-file, v1).
GetFile(ctx context.Context, path string) ([]byte, error)
}
HandleServer is the host-side backend a Client binds to. Every transport (Local, SSH-POSIX, SSH-Windows, WinRM) implements it; the Client dispatches plugin handle-op requests to it. Handle embeds this so the subset relationship between handle ops and the full plugin Handle stays explicit.
func NoopHandleServer ¶
func NoopHandleServer() HandleServer
NoopHandleServer returns a HandleServer whose methods report that no target is bound. It is intended for plugin inspection (plugin list/info/staging) where there is no target to operate against.
type InitializeParams ¶
type InitializeParams struct {
ProtocolVersion string `json:"protocol_version"`
Target TargetInfo `json:"target"`
}
InitializeParams is sent by the host in the initialize request.
type InitializeResult ¶
type InitializeResult struct {
Name string `json:"name"`
Version string `json:"version"`
ProtocolVersion string `json:"protocol_version"`
}
InitializeResult is the plugin's initialize response. ProtocolVersion must equal ProtocolVersion or the host rejects the plugin with a plugin_protocol error.
type Module ¶
type Module interface {
// Name returns the module's canonical name (e.g. "my-module").
Name() string
// Version returns the module's semantic version.
Version() string
// Check reports whether the system is already in the desired state.
// NeedsChange must be true if the system is NOT yet in the desired state
// (i.e., Apply should be called). Target effects go through h.
Check(args map[string]any, h Handle) (CheckResult, error)
// Apply brings the system into the desired state, using h for all target
// effects.
Apply(args map[string]any, h Handle) (ApplyResult, error)
}
Module is the interface plugin authors implement. Check and Apply receive a Handle: ALL target effects flow through it, including against the local target. This brings plugins in line with first-party modules.
One target op is in flight per session. For high-latency transports, batch work into a single script-shaped RunCommand instead of many round trips.
type OutputFunc ¶
type OutputFunc func(line string)
OutputFunc is called for each line of streaming output emitted during Check or Apply. On the host side it forwards plugin output notifications to the runner; on the plugin side it is exposed through Handle.Output.
type PluginStatus ¶
type PluginStatus struct {
Name string
Path string
Source string
Version string
Initialized bool
ErrorMessage string
}
PluginStatus describes a discovered plugin plus initialization status.
func Inspect ¶
func Inspect(opts DiscoveryOptions) ([]PluginStatus, error)
Inspect initializes each discovered plugin and returns its reported version or the initialization failure.
func InspectPlugin ¶
func InspectPlugin(path, source string) PluginStatus
InspectPlugin initializes a single plugin executable and returns its status.
type ProtocolError ¶
ProtocolError reports a plugin that failed the protocol-version handshake. Pre-v1 plugins (no protocol_version) and protocol mismatches both surface as this typed error so the host can raise the distinct plugin_protocol class.
func (*ProtocolError) Error ¶
func (e *ProtocolError) Error() string
type TargetInfo ¶
type TargetInfo struct {
Family string `json:"family"`
Name string `json:"name"`
Version string `json:"version"`
Arch string `json:"arch"`
Hostname string `json:"hostname"`
PackageManager string `json:"package_manager"`
Init string `json:"init"`
RuntimeKind string `json:"runtime_kind"`
}
TargetInfo is the enriched target context delivered to a plugin at initialize. Absent signals are empty strings, never missing keys, so plugin code can branch on them with simple equality. RuntimeKind tells the plugin which shell RunCommand speaks (posix-sh or windows-powershell).