Documentation
¶
Index ¶
- Constants
- Variables
- func IsHandshakeLine(line string) bool
- func Redact(line string) string
- type CommandSpec
- type Config
- type ExecRunner
- type Handshake
- type Health
- type HealthChecker
- type HealthFailurePolicy
- type HealthTarget
- type Installation
- type Instance
- type InstanceSnapshot
- type InstanceSpec
- type Isolation
- type Kind
- type LogEntry
- type Manager
- func (m *Manager) ApplicationClient(pluginID string) (application.ApplicationClient, error)
- func (m *Manager) ApplicationClientForInstance(tenant, id string) (application.ApplicationClient, error)
- func (m *Manager) Close() error
- func (m *Manager) CreateInstance(spec InstanceSpec) (Instance, error)
- func (m *Manager) Disable(tenant, id string) error
- func (m *Manager) DriverClient(pluginID string) (driver.DriverClient, error)
- func (m *Manager) DriverClientForInstance(tenant, id string) (driver.DriverClient, error)
- func (m *Manager) Enable(tenant, id string) error
- func (m *Manager) ListInstallations() []Installation
- func (m *Manager) ListInstances(tenant string) []InstanceSnapshot
- func (m *Manager) Metrics(tenant, id string) (Metrics, error)
- func (m *Manager) ReconcileInstance(ctx context.Context, spec InstanceSpec, enabled bool) error
- func (m *Manager) RegisterInstallation(inst Installation) error
- func (m *Manager) Remove(tenant, id string, opts ...RemoveOption) (RemoveResult, error)
- func (m *Manager) Snapshot(tenant, id string) (InstanceSnapshot, error)
- func (m *Manager) Start(tenant, id string) error
- type ManagerOptions
- type Metrics
- type MetricsCollector
- type MetricsTarget
- type Process
- type RemoveOption
- type RemoveResult
- type Runner
- type Snapshot
- type State
- type Supervisor
- func (s *Supervisor) ApplicationClient() application.ApplicationClient
- func (s *Supervisor) Disable()
- func (s *Supervisor) DriverClient() driver.DriverClient
- func (s *Supervisor) Enable()
- func (s *Supervisor) Logs() []LogEntry
- func (s *Supervisor) Restart()
- func (s *Supervisor) Run(ctx context.Context) error
- func (s *Supervisor) Snapshot() Snapshot
- func (s *Supervisor) State() State
Constants ¶
const ( EnvPluginID = "CLOUDPATH_PLUGIN_ID" EnvProtocol = "CLOUDPATH_PROTOCOL" EnvProtocolVersion = "CLOUDPATH_PROTOCOL_VERSION" EnvLaunchID = "CLOUDPATH_LAUNCH_ID" EnvProof = "CLOUDPATH_PROOF" EnvPluginEndpoint = "CLOUDPATH_PLUGIN_ENDPOINT" // EnvHandshakeCookie is kept as an alias for EnvProof so earlier launch // identity readers and the existing test harness keep working during the // migration. New code should use EnvProof. EnvHandshakeCookie = "CLOUDPATH_HANDSHAKE_COOKIE" )
Environment variables used to pass the launch identity and expected protocol into a plugin process. The plugin must echo these back in its handshake line so the host can reject mis-wired or malicious starts.
const ( EnvTenant = "CLOUDPATH_TENANT" EnvInstanceID = "CLOUDPATH_INSTANCE_ID" )
Environment variables injected into a per-instance plugin process so it can tell which tenant/instance it is serving. Shared processes serve several instances and are therefore not given a single identity.
const ConfigPathKey = "path"
ConfigPathKey is the existing Host-only config-file reference. It is not a plugin JSON property and must not be forwarded to ConfigureInstance.
const HandshakeMarker = "CP1"
HandshakeMarker is the fixed first field of a plugin handshake line.
Variables ¶
var ( ErrInstallationNotFound = errors.New("pluginhost: installation not found") ErrInstallationExists = errors.New("pluginhost: installation already registered") ErrInstanceNotFound = errors.New("pluginhost: instance not found") ErrInstanceExists = errors.New("pluginhost: instance already exists") ErrInvalidArgument = errors.New("pluginhost: invalid argument") ErrAmbiguousInstance = errors.New("pluginhost: multiple running processes require an instance target") )
Sentinel errors returned by the Manager. Callers can compare with errors.Is to distinguish "does not exist" from other failures.
var ErrConnectorUnsupported = errors.New("pluginhost: connector plugin kind is not supported")
ErrConnectorUnsupported reports that a Connector plugin cannot be launched by the process host. It is returned before any process or endpoint is created.
Functions ¶
func IsHandshakeLine ¶
IsHandshakeLine reports whether line is a structured handshake line. Any such line after the first one is a protocol violation.
Types ¶
type CommandSpec ¶
CommandSpec is the argv-separated description of one plugin process launch. It never contains a shell command string; Path and Args are passed to os/exec verbatim.
type Config ¶
type Config struct {
PluginID string
Kind Kind
Protocol string
ProtocolVersion uint32
Command CommandSpec
// HandshakeTimeout is how long the host waits for the unique stdout
// handshake line and the socket authentication frame before killing the
// process and counting a crash.
HandshakeTimeout time.Duration
// ShutdownTimeout is the graceful shutdown deadline; after it the process
// is killed.
ShutdownTimeout time.Duration
// HealthCheckInterval is how often the established RPC client is probed.
HealthCheckInterval time.Duration
// MaxRestarts is the crash-loop budget: at most this many re-launches are
// attempted before the plugin is disabled. Zero disables restarts.
MaxRestarts int
BaseBackoff time.Duration
MaxBackoff time.Duration
// LogBufferSize caps the retained redacted log lines per plugin.
LogBufferSize int
// Jitter randomizes backoff; default is full jitter in [0, d]. Override
// with a deterministic function in tests.
Jitter func(time.Duration) time.Duration
}
Config configures one supervised plugin process.
type ExecRunner ¶
type ExecRunner struct{}
ExecRunner is the production Runner backed by os/exec.
func (ExecRunner) Start ¶
func (ExecRunner) Start(spec CommandSpec) (Process, error)
Start launches the process and attaches platform process-tree control (Job Object on Windows, process group elsewhere).
type Handshake ¶
type Handshake struct {
Marker string
PluginID string
Protocol string
ProtocolVersion uint32
Transport string
Endpoint string
RPC string
LaunchID string
Proof string
}
Handshake is the parsed form of a plugin handshake line:
CP1|<plugin-id>|<protocol>=<version>|<transport>|<endpoint>|<rpc>|<launch-id>|<proof>
func ParseHandshake ¶
ParseHandshake parses and structurally validates a handshake line. It does not compare against the expected plugin id, protocol or cookie; that is done by Supervisor.validateHandshake.
type Health ¶
type Health uint8
Health is the coarse health grade reported by a HealthChecker for one plugin instance. It is deliberately separate from the Supervisor process State: a process can be alive (Healthy process state) while its protocol health is Degraded.
type HealthChecker ¶
type HealthChecker interface {
Check(ctx context.Context, target HealthTarget) (Health, error)
}
HealthChecker probes one plugin instance. Implementations must return quickly and are called periodically by the Manager, outside the Manager lock.
type HealthFailurePolicy ¶
type HealthFailurePolicy uint8
HealthFailurePolicy selects the Manager action once an instance accumulates HealthFailureThreshold consecutive failed probes.
const ( // HealthPolicyDisable stops the process. It is the default and does not // touch the Supervisor crash budget. HealthPolicyDisable HealthFailurePolicy = iota // HealthPolicyRestart performs a supervised in-place restart without // incrementing the Supervisor crash/restart budget. HealthPolicyRestart )
func (HealthFailurePolicy) String ¶
func (p HealthFailurePolicy) String() string
String returns a stable, human-readable policy name.
type HealthTarget ¶
HealthTarget identifies the plugin instance being probed.
type Installation ¶
type Installation struct {
PluginID string
Version string
Path string
// Kind selects the protocol client the host builds for this installation.
// A zero value means KindDriver.
Kind Kind
}
Installation is one installed version of a plugin on this node. It is the node-level artifact that PluginInstance values are bound to; the same plugin may have multiple versions installed side by side for rolling migrations.
type Instance ¶
type Instance struct {
ID string
Tenant string
PluginID string
Version string
Config map[string]string
Isolation Isolation
}
Instance is one bound, running unit of a plugin. It is always owned by exactly one tenant and bound to exactly one installation version at a time.
type InstanceSnapshot ¶
type InstanceSnapshot struct {
Tenant string
InstanceID string
PluginID string
Version string
Isolation Isolation
Enabled bool
State State
Health Health
ConsecutiveFailures int
Restarts int
Crashes int
Launches int
Config map[string]string
}
InstanceSnapshot is a point-in-time view of one instance for observability and tests. State is the serving process lifecycle state from the Supervisor; Health is the Manager health-loop grade.
type InstanceSpec ¶
type InstanceSpec struct {
ID string
Tenant string
PluginID string
Version string
Config map[string]string
Isolation Isolation
}
InstanceSpec is the input for CreateInstance.
type Isolation ¶
type Isolation uint8
Isolation selects whether an instance shares a plugin process with other instances of the same installation, or gets its own dedicated process.
type Kind ¶
type Kind uint8
Kind is the plugin contribution kind from the manifest. It selects which protocol client the host builds after the socket handshake: Driver and Application map to their SDK clients; Connector is explicitly unsupported by the process host.
func ParseKind ¶
ParseKind parses a manifest kind string case-insensitively. It accepts the canonical manifest values ("Driver", "Application", "Connector") and the wire protocol names ("driver", "application", "connector").
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns plugin installations, instances and their supervised processes, plus the periodic health and metrics framework. It is safe for concurrent use.
func NewManager ¶
func NewManager(opts ManagerOptions) *Manager
NewManager builds a Manager and starts its background health loop. Call Close to stop the loop and every supervised process.
func (*Manager) ApplicationClient ¶ added in v0.2.3
func (m *Manager) ApplicationClient(pluginID string) (application.ApplicationClient, error)
ApplicationClient is the application-kind equivalent of DriverClient. It rejects ambiguous plugin-only lookups instead of selecting an arbitrary process.
func (*Manager) ApplicationClientForInstance ¶ added in v0.2.14
func (m *Manager) ApplicationClientForInstance(tenant, id string) (application.ApplicationClient, error)
ApplicationClientForInstance resolves the exact enabled tenant/instance process; the returned client must be re-resolved after a restart.
func (*Manager) Close ¶
Close stops the health loop and gracefully shuts down every supervised process. It is idempotent.
func (*Manager) CreateInstance ¶
func (m *Manager) CreateInstance(spec InstanceSpec) (Instance, error)
CreateInstance binds a new instance to an installed version. The instance is created stopped; call Start to launch it.
func (*Manager) Disable ¶
Disable stops the instance. For a shared process it only stops the process when no other enabled instance still uses it.
func (*Manager) DriverClient ¶ added in v0.2.0
func (m *Manager) DriverClient(pluginID string) (driver.DriverClient, error)
DriverClient returns a session-scoped client for an unambiguous plugin process. Multiple enabled instances may share it; multiple processes require DriverClientForInstance. Callers must re-resolve after a process restart.
func (*Manager) DriverClientForInstance ¶ added in v0.2.14
func (m *Manager) DriverClientForInstance(tenant, id string) (driver.DriverClient, error)
DriverClientForInstance resolves exactly one enabled tenant/instance binding, with no fallback to another version, process or tenant.
func (*Manager) Enable ¶
Enable re-enables a previously disabled instance and relaunches its process.
func (*Manager) ListInstallations ¶
func (m *Manager) ListInstallations() []Installation
ListInstallations returns all registered installations sorted by plugin id then version.
func (*Manager) ListInstances ¶
func (m *Manager) ListInstances(tenant string) []InstanceSnapshot
ListInstances returns a snapshot for every instance owned by tenant, sorted by instance id.
func (*Manager) Metrics ¶
Metrics returns a factual resource/health snapshot for one instance. It combines process-level observability from MetricsCollector with the restart count and last-healthy time maintained by the Manager.
func (*Manager) ReconcileInstance ¶ added in v0.2.14
ReconcileInstance applies a complete instance definition. Candidate processes must establish an authenticated, serving session before replacing a live binding. Config updates use the existing per-instance RPC, not process-wide environment variables, so shared siblings (including other tenants) stay up. No plugin data is removed. A disabled definition need not be installed.
func (*Manager) RegisterInstallation ¶
func (m *Manager) RegisterInstallation(inst Installation) error
RegisterInstallation records one installed plugin version. It fails if the same (plugin id, version) is already registered.
func (*Manager) Remove ¶
func (m *Manager) Remove(tenant, id string, opts ...RemoveOption) (RemoveResult, error)
Remove deletes an instance and stops its process when it is no longer needed. Plugin data is preserved by default; use WithPurge to delete it.
type ManagerOptions ¶
type ManagerOptions struct {
Runner Runner
Logger *slog.Logger
Protocol string
ProtocolVersion uint32
HealthChecker HealthChecker
MetricsCollector MetricsCollector
// HealthCheckInterval is how often running instances are probed.
HealthCheckInterval time.Duration
// HealthFailureThreshold is the number of consecutive failed probes before
// HealthFailurePolicy is applied.
HealthFailureThreshold int
// HealthFailurePolicy selects restart or disable after the threshold.
HealthFailurePolicy HealthFailurePolicy
// Supervisor tuning, forwarded to every supervised process.
HandshakeTimeout time.Duration
ShutdownTimeout time.Duration
MaxRestarts int
BaseBackoff time.Duration
MaxBackoff time.Duration
LogBufferSize int
Jitter func(time.Duration) time.Duration
// CommandArgs/CommandEnv are the default argv/env used for every launched
// process (Env is supplemented with the launch identity).
CommandArgs []string
CommandEnv []string
}
ManagerOptions configures a Manager. All fields are optional; sensible defaults are applied when a field is left zero.
type Metrics ¶
type Metrics struct {
// CPUTime is total CPU time consumed by the plugin process.
CPUTime time.Duration
// RSSBytes is resident set size in bytes (0 when unavailable).
RSSBytes int64
// Handles is the open handle count, or -1 when unavailable.
Handles int
// Goroutines is the live goroutine count, or -1 when unavailable.
Goroutines int
// MessageRate is messages per second over the observation window.
MessageRate float64
// RestartCount is the process restart count maintained by the Manager.
RestartCount int
// LastHealthy is the last time the health loop observed HEALTHY (zero when
// never observed).
LastHealthy time.Time
}
Metrics is a factual point-in-time snapshot of one plugin instance. Fields the current platform cannot observe are reported as unavailable rather than fabricated.
type MetricsCollector ¶
type MetricsCollector interface {
Collect(ctx context.Context, target MetricsTarget) (Metrics, error)
}
MetricsCollector observes process-level resource metrics for one instance. Implementations must return quickly and may report unavailable fields.
type MetricsTarget ¶
MetricsTarget identifies the plugin instance whose metrics are collected.
type Process ¶
type Process interface {
Wait() error
Signal(os.Signal) error
Kill() error
Pid() int
Stdout() io.ReadCloser
Stderr() io.ReadCloser
}
Process is the running plugin process as seen by the Supervisor. It is the seam that lets tests inject an in-memory fake instead of a real binary.
type RemoveOption ¶
type RemoveOption func(*removeOptions)
RemoveOption changes Remove behavior.
func WithPurge ¶
func WithPurge() RemoveOption
WithPurge requests that plugin data be deleted during Remove. Purge is a separate, explicit, high-risk option and is off by default.
type RemoveResult ¶
type RemoveResult struct {
// Purged is true only when an explicit purge option was requested.
Purged bool
// DataPreserved is true when plugin data was left in place. It is the
// default Remove semantics.
DataPreserved bool
}
RemoveResult reports what happened to plugin data during Remove.
type Runner ¶
type Runner interface {
Start(spec CommandSpec) (Process, error)
}
Runner starts plugin processes from a CommandSpec.
type Snapshot ¶
type Snapshot struct {
State State
Crashes int
Restarts int
Launches int
HandshakeCompleted bool
Backoffs []time.Duration
// Kind is the protocol kind the supervisor was configured for.
Kind Kind
// Endpoint is the most recent launch endpoint (loopback TCP or Unix
// socket path). It is a local-only address and safe to surface.
Endpoint string
// RPCConnections is the number of authenticated RPC connections the host
// has accepted across the current launch. Rejected proofs never count.
RPCConnections int
}
Snapshot is a point-in-time view of the supervisor for observability and tests.
type State ¶
type State uint8
State is the lifecycle state of one plugin process under the Supervisor. The canonical uppercase names are the UI/observability contract and must remain stable.
func (State) CanTransition ¶
CanTransition reports whether from -> to is a legal transition.
type Supervisor ¶
type Supervisor struct {
// contains filtered or unexported fields
}
Supervisor owns the lifecycle of one plugin process.
func NewSupervisor ¶
func NewSupervisor(cfg Config, runner Runner, logger *slog.Logger) *Supervisor
NewSupervisor builds a Supervisor. A nil runner uses the production ExecRunner; a nil logger discards logs.
func (*Supervisor) ApplicationClient ¶ added in v0.2.3
func (s *Supervisor) ApplicationClient() application.ApplicationClient
ApplicationClient returns the ApplicationClient of the current launch for application-kind plugins, or nil while the process is starting, crashed, or disabled. The returned client is tied to the current session and must be re-resolved after a restart.
func (*Supervisor) Disable ¶
func (s *Supervisor) Disable()
Disable requests an immediate stop and prevents any further launches until Enable is called.
func (*Supervisor) DriverClient ¶ added in v0.2.0
func (s *Supervisor) DriverClient() driver.DriverClient
DriverClient returns the DriverClient of the current launch, or nil while the process is starting, crashed, or disabled. The returned client is tied to the current session and must be re-resolved after a restart.
func (*Supervisor) Enable ¶
func (s *Supervisor) Enable()
Enable allows the supervisor to start the plugin again.
func (*Supervisor) Logs ¶
func (s *Supervisor) Logs() []LogEntry
Logs returns the retained, already-redacted plugin log lines.
func (*Supervisor) Restart ¶
func (s *Supervisor) Restart()
Restart requests a supervised in-place restart: the current process is killed and a fresh one is launched inside the same Run loop without touching the crash/restart budget. The Manager health failure policy uses this so health restarts are never counted as crashes.
func (*Supervisor) Run ¶
func (s *Supervisor) Run(ctx context.Context) error
Run supervises the plugin until ctx is canceled. On cancellation it performs a graceful shutdown (RPC Shutdown, then signal, then kill after ShutdownTimeout). Run returns nil after a graceful stop and ctx.Err() when it was already shutting down.
func (*Supervisor) Snapshot ¶
func (s *Supervisor) Snapshot() Snapshot
Snapshot returns a point-in-time view of the supervisor.
func (*Supervisor) State ¶
func (s *Supervisor) State() State
State returns the current lifecycle state.