extensions

package
v1.8.1 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Overview

Package extensions runs out-of-process gopherstack extensions: executables or container images that register routes and hooks over a local control API.

Index

Constants

View Source
const (
	RestartNever     = "never"
	RestartOnFailure = "on-failure"
	RestartAlways    = "always"
)

Restart policies.

Variables

View Source
var (
	ErrUnknownExtension = errors.New("unknown extension")
	ErrNotRunning       = errors.New("extension manager is not running")
)

Errors returned by the management operations.

View Source
var (
	ErrInvalidSpec   = errors.New("invalid extension spec")
	ErrInvalidConfig = errors.New("invalid extensions config")
)

Errors returned by config loading and validation.

View Source
var ErrInvalidRegistration = errors.New("invalid registration")

ErrInvalidRegistration is returned for a rejected registration payload.

Functions

This section is empty.

Types

type Config

type Config struct {
	FailOpen    *bool         `yaml:"fail_open"`
	Extensions  []Spec        `yaml:"extensions"`
	HookTimeout time.Duration `yaml:"hook_timeout"`
}

Config is the extensions config file.

func LoadConfig

func LoadConfig(s Settings) (Config, error)

LoadConfig merges the config file and inline flags into one validated Config.

func (Config) Enabled

func (c Config) Enabled() bool

Enabled reports whether any extension is declared.

func (Config) FailOpenDefault

func (c Config) FailOpenDefault() bool

FailOpenDefault is the fail-open default for request hooks (true unless configured).

type HookResponse

type HookResponse struct {
	Headers map[string]string `json:"headers"`
	Body    []byte            `json:"body"`
	Status  int               `json:"status"`
}

HookResponse is a reply an extension (or a failed closed hook) wants sent to the client.

func (*HookResponse) Write

func (r *HookResponse) Write(w http.ResponseWriter)

Write sends the response.

type HookSet

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

HookSet is the set of request hooks that apply to one service for one request.

func (*HookSet) HasPost

func (h *HookSet) HasPost() bool

HasPost reports whether any hook wants the response.

func (*HookSet) Post

func (h *HookSet) Post(r *http.Request, rec *Recorder) *HookResponse

Post runs the post-response hooks; replies may replace status, headers and body in rec.

func (*HookSet) Pre

func (h *HookSet) Pre(r *http.Request) *HookResponse

Pre runs the pre-request hooks. A non-nil result short-circuits the request; the request body is restored and any set_headers are applied to r.

type Hooks

type Hooks struct {
	OnStartup  string        `json:"on_startup,omitempty"`
	OnReady    string        `json:"on_ready,omitempty"`
	OnShutdown string        `json:"on_shutdown,omitempty"`
	Request    []RequestHook `json:"request,omitempty"`
}

Hooks are the extension's lifecycle and request callbacks (paths on its endpoint).

type Info

type Info struct {
	Registration *Registration `json:"registration,omitempty"`
	Name         string        `json:"name"`
	Type         string        `json:"type"`
	Status       Status        `json:"status"`
	Endpoint     string        `json:"endpoint,omitempty"`
	LastError    string        `json:"last_error,omitempty"`
	Restarts     int           `json:"restarts"`
}

Info is the public, token-free view of an extension.

type Manager

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

Manager owns extension lifecycles, claims and hooks.

func New

func New(cfg Config, opts Options) *Manager

New builds a manager for cfg (already normalized by LoadConfig).

func (*Manager) Enabled

func (m *Manager) Enabled() bool

Enabled reports whether any extension is configured.

func (*Manager) Hooks

func (m *Manager) Hooks(service string) *HookSet

Hooks returns the request hooks registered for service, or nil when there are none.

func (*Manager) List

func (m *Manager) List() []Info

List returns the management view of all extensions.

func (*Manager) MarkReady

func (m *Manager) MarkReady(ctx context.Context)

MarkReady fires on_ready for registered extensions and for any that register later.

func (*Manager) Output

func (m *Manager) Output(name string) ([]string, error)

Output returns the recent captured stdout/stderr lines (already redacted).

func (*Manager) Restart

func (m *Manager) Restart(name string) error

Restart recycles a running extension, or relaunches one that failed or stopped.

func (*Manager) Route

func (m *Manager) Route(r *http.Request, shadowed bool) http.Handler

Route returns the handler for r if an extension claims it, else nil. shadowed means a built-in service already matched; only allow_override extensions may take such requests.

func (*Manager) ServeList

func (m *Manager) ServeList(w http.ResponseWriter, _ *http.Request)

ServeList handles GET /_gopherstack/extensions.

func (*Manager) ServeOutput

func (m *Manager) ServeOutput(w http.ResponseWriter, r *http.Request, name string)

ServeOutput handles GET /_gopherstack/extensions/{name}/output (loopback only).

func (*Manager) ServeRegister

func (m *Manager) ServeRegister(w http.ResponseWriter, r *http.Request)

ServeRegister handles POST /_gopherstack/extensions/register.

func (*Manager) ServeRestart

func (m *Manager) ServeRestart(w http.ResponseWriter, r *http.Request, name string)

ServeRestart handles POST /_gopherstack/extensions/{name}/restart (loopback only).

func (*Manager) Start

func (m *Manager) Start(ctx context.Context)

Start launches every extension supervisor; it returns immediately.

func (*Manager) Stop

func (m *Manager) Stop(ctx context.Context)

Stop calls on_shutdown, then stops every extension, bounded by ctx.

type Options

type Options struct {
	Logger *slog.Logger
	// NewRuntime builds the container runtime on first use; nil disables image extensions.
	NewRuntime func() (container.Runtime, error)
	// ControlURL is the base URL extensions use to reach the control API.
	ControlURL string
}

Options wires the manager to its host.

type Recorder

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

Recorder buffers a response so post hooks can inspect and rewrite it before Commit.

func NewRecorder

func NewRecorder(w http.ResponseWriter) *Recorder

NewRecorder wraps w; nothing reaches w until Commit.

func (*Recorder) Commit

func (r *Recorder) Commit()

Commit writes the buffered response to the underlying writer.

func (*Recorder) Header

func (r *Recorder) Header() http.Header

Header returns the buffered headers.

func (*Recorder) Status

func (r *Recorder) Status() int

Status is the recorded status (200 when none was written).

func (*Recorder) Write

func (r *Recorder) Write(b []byte) (int, error)

Write buffers body bytes.

func (*Recorder) WriteHeader

func (r *Recorder) WriteHeader(code int)

WriteHeader records the status.

type Registration

type Registration struct {
	Name     string `json:"name"`
	Version  string `json:"version,omitempty"`
	Endpoint string `json:"endpoint,omitempty"`
	Routes   Routes `json:"routes"`
	Hooks    Hooks  `json:"hooks"`
}

Registration is the body of POST /_gopherstack/extensions/register.

type RequestHook

type RequestHook struct {
	FailOpen  *bool    `json:"fail_open,omitempty"`
	Pre       string   `json:"pre,omitempty"`
	Post      string   `json:"post,omitempty"`
	Services  []string `json:"services"`
	TimeoutMs int      `json:"timeout_ms,omitempty"`
}

RequestHook asks gopherstack to call the extension around matched services.

type Routes

type Routes struct {
	PathPrefixes   []string `json:"path_prefixes,omitempty"`
	Hosts          []string `json:"hosts,omitempty"`
	TargetPrefixes []string `json:"target_prefixes,omitempty"`
}

Routes are the requests an extension claims.

type Settings

type Settings struct {
	Config string `` //nolint:lll // config struct tags are intentionally verbose
	/* 138-byte string literal not displayed */
	Inline []string `` //nolint:lll // config struct tags are intentionally verbose
	/* 149-byte string literal not displayed */
}

Settings is embedded in the root CLI.

type Spec

type Spec struct {
	Env            map[string]string `yaml:"env"`
	Name           string            `yaml:"name"`
	Image          string            `yaml:"image"`
	Restart        string            `yaml:"restart"`
	HealthPath     string            `yaml:"health_path"`
	ControlURL     string            `yaml:"control_url"`
	Command        []string          `yaml:"command"`
	Args           []string          `yaml:"args"`
	Port           int               `yaml:"port"`
	MaxRestarts    int               `yaml:"max_restarts"`
	RestartBackoff time.Duration     `yaml:"restart_backoff"`
	StartTimeout   time.Duration     `yaml:"start_timeout"`
	HealthInterval time.Duration     `yaml:"health_interval"`
	HealthTimeout  time.Duration     `yaml:"health_timeout"`
	HealthFailures int               `yaml:"health_failures"`
	AllowOverride  bool              `yaml:"allow_override"`
}

Spec declares one extension: either Command (a host process) or Image (a container).

func ParseInline

func ParseInline(v string) (Spec, error)

ParseInline parses name=command args or name=image:REF.

type Status

type Status string

Status is an extension's lifecycle state.

const (
	StatusStarting   Status = "starting"
	StatusReady      Status = "ready"
	StatusUnhealthy  Status = "unhealthy"
	StatusRestarting Status = "restarting"
	StatusFailed     Status = "failed"
	StatusStopped    Status = "stopped"
)

Lifecycle states reported by the management API.

Jump to

Keyboard shortcuts

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