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) Close() error
- func (m *Manager) CreateInstance(spec InstanceSpec) (Instance, error)
- func (m *Manager) Disable(tenant, id string) 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) 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
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 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") )
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) 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) 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) 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) Disable ¶
func (s *Supervisor) Disable()
Disable requests an immediate stop and prevents any further launches until Enable is called.
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.