controlapi

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package controlapi implements vmflow's internal daemon management transport.

It exists for the bundled CLI, TUI, and bot. It is not a supported public integration API and does not provide compatibility guarantees for external callers.

Index

Constants

View Source
const (
	RoleAdmin  = config.AuthRoleAdmin
	RoleViewer = config.AuthRoleViewer
)
View Source
const ManagementAPIVersion = "1"

ManagementAPIVersion identifies the internal daemon management contract.

Variables

This section is empty.

Functions

func APIStatus added in v0.3.0

func APIStatus(err error) int

APIStatus returns the HTTP status embedded in err, or 0 if err is not an APIError.

func BuildClientTLSConfig added in v0.3.0

func BuildClientTLSConfig(o ClientTLSOptions) (*tls.Config, error)

BuildClientTLSConfig builds a *tls.Config for a control API client. MinVersion is pinned to TLS 1.2.

func BuildServerTLSConfig added in v0.3.0

func BuildServerTLSConfig(cfg config.ControlTLSConfig) (*tls.Config, error)

BuildServerTLSConfig builds a *tls.Config for the control API from cfg. It returns nil (plain HTTP) when neither cert nor key is configured. Setting ClientCAFile enables mutual TLS: every client must present a certificate signed by that CA.

func CloneRules added in v0.3.0

func CloneRules(rules []engine.Rule) []engine.Rule

CloneRules deep-copies a rule slice including nested string slices.

func IsBotValidationError added in v0.3.0

func IsBotValidationError(err error) bool

func NewHTTPClient added in v0.3.0

func NewHTTPClient(opts ClientTLSOptions, timeout time.Duration) (*http.Client, error)

NewHTTPClient returns an *http.Client for talking to the control API. When no TLS option is set it returns http.DefaultClient (preserving existing behavior). A non-zero timeout applies an overall request deadline.

func NewHandler

func NewHandler(runtime *Runtime) http.Handler

func NormalizeETag added in v0.3.0

func NormalizeETag(value string) string

NormalizeETag quotes a bare ETag value; already-quoted, weak, or wildcard values pass through unchanged.

func SaveSetupConfig added in v0.3.0

func SaveSetupConfig(path string, update SetupConfigUpdate) (config.File, error)

SaveSetupConfig validates and persists the language/auth/rules chosen by the first-run workflow. Existing files use the same guarded atomic replacement as live TUI rule management. A missing file is created exclusively with mode 0600.

func SetupConfigCommitted added in v0.3.0

func SetupConfigCommitted(err error) bool

SetupConfigCommitted reports whether SaveSetupConfig reached its filesystem commit point before returning an error (for example, a later directory-sync failure). Callers must not roll back companion state in that case.

Types

type APIError added in v0.3.0

type APIError struct {
	StatusCode int
	Message    string
	Body       []byte
}

APIError preserves the HTTP status so callers can distinguish auth, validation, conflicts, and transient server failures.

func (*APIError) Error added in v0.3.0

func (e *APIError) Error() string

type ApplyResponse added in v0.3.0

type ApplyResponse struct {
	Revision       string             `json:"revision"`
	Writable       bool               `json:"writable"`
	UDPMaxSessions int                `json:"udp_max_sessions"`
	Rules          []engine.Rule      `json:"rules"`
	Result         engine.ApplyResult `json:"result"`
	ETag           string             `json:"-"`
}

ApplyResponse is the PUT /v1/config/rules success payload.

func (*ApplyResponse) Snapshot added in v0.3.0

func (r *ApplyResponse) Snapshot() *ConfigRulesResponse

Snapshot builds a ConfigRulesResponse from an apply result.

type AuthInfo

type AuthInfo struct {
	Name string `json:"name"`
	Role string `json:"role"`
}

AuthInfo describes the authenticated Control API caller.

func AuthInfoFromContext

func AuthInfoFromContext(ctx context.Context) (AuthInfo, bool)

AuthInfoFromContext returns caller auth info from a request context.

type Authenticator

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

Authenticator validates Control API bearer tokens.

func NewAuthenticator

func NewAuthenticator(cfg config.AuthConfig) *Authenticator

NewAuthenticator builds an authenticator from config.

func (*Authenticator) Authenticate

func (a *Authenticator) Authenticate(r *http.Request) (AuthInfo, bool)

Authenticate validates the Authorization header and returns caller info.

func (*Authenticator) Enabled

func (a *Authenticator) Enabled() bool

Enabled returns whether authentication is enforced.

type BotConfigRequest added in v0.3.0

type BotConfigRequest struct {
	BotToken        string `json:"bot_token"`
	BotChat         int64  `json:"bot_chat"`
	BotControlToken string `json:"bot_control_token"`
}

BotConfigRequest is the PUT /v1/config/bot body.

type BotConfigResponse added in v0.3.0

type BotConfigResponse struct {
	Revision        string `json:"revision"`
	BotToken        string `json:"bot_token"`
	BotChat         int64  `json:"bot_chat"`
	BotControlToken string `json:"bot_control_token"`
	Running         bool   `json:"running"`
	ETag            string `json:"-"`
}

BotConfigResponse is the GET /v1/config/bot payload. Tokens are plaintext (admin-only endpoint); the TUI masks them for display.

type BotController added in v0.3.0

type BotController interface {
	// Apply stops any running bot and starts a new one with settings. If Token
	// or ChatID are zero, the bot is stopped and not restarted.
	Apply(settings BotSettings) error
	// Stop stops the running bot without changing persisted configuration.
	Stop() error
	// Running reports whether a bot goroutine is currently active.
	Running() bool
}

BotController manages the Telegram bot lifecycle at runtime, allowing the bot to be started, stopped, and reconfigured without restarting the daemon. It is implemented by the bot package and injected into Runtime so controlapi does not need to import bot (avoiding an import cycle).

type BotSettings added in v0.3.0

type BotSettings struct {
	Token        string
	ChatID       int64
	ControlToken string
}

BotSettings is the Telegram bot configuration managed at runtime.

type BotUnavailableError added in v0.3.0

type BotUnavailableError struct {
	Err error
}

BotUnavailableError reports that readiness could not be established due to a transient Telegram or network failure.

func (*BotUnavailableError) Error added in v0.3.0

func (err *BotUnavailableError) Error() string

func (*BotUnavailableError) Unwrap added in v0.3.0

func (err *BotUnavailableError) Unwrap() error

type BotValidationError added in v0.3.0

type BotValidationError struct {
	Err error
}

BotValidationError reports bot settings that Telegram has rejected. Error is intentionally generic because low-level HTTP errors may contain the bot token in their request URL.

func (*BotValidationError) Error added in v0.3.0

func (err *BotValidationError) Error() string

func (*BotValidationError) Unwrap added in v0.3.0

func (err *BotValidationError) Unwrap() error

type Client added in v0.3.0

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

Client calls vmflow's internal daemon management transport. It is shared by the bundled TUI, CLI, and Telegram bot.

func NewClient added in v0.3.0

func NewClient(baseURL, token string) *Client

NewClient returns an internal management client for baseURL with the given bearer token. The token may be empty for read-only access.

func (*Client) Apply added in v0.3.0

func (c *Client) Apply(ctx context.Context, match string, draft ConfigRulesRequest) (*ApplyResponse, error)

Apply replaces the managed rules configuration. match is the If-Match ETag from a prior ConfigRules call (optimistic concurrency).

func (*Client) ApplyBotConfig added in v0.3.0

func (c *Client) ApplyBotConfig(ctx context.Context, match string, req BotConfigRequest) (*BotConfigResponse, error)

ApplyBotConfig updates the bot configuration (persisted to config.yaml) and restarts the bot goroutine. match is the If-Match ETag from a prior BotConfig.

func (*Client) BaseURL added in v0.3.0

func (c *Client) BaseURL() string

BaseURL returns the internal management base URL configured for the client.

func (*Client) BotConfig added in v0.3.0

func (c *Client) BotConfig(ctx context.Context) (*BotConfigResponse, error)

BotConfig fetches the current bot configuration and running state.

func (*Client) ConfigRules added in v0.3.0

func (c *Client) ConfigRules(ctx context.Context) (*ConfigRulesResponse, error)

func (*Client) CurrentPrecheck added in v0.3.0

func (c *Client) CurrentPrecheck(ctx context.Context) (*CurrentPrecheckResponse, error)

CurrentPrecheck validates the daemon's current on-disk configuration. HTTP 400 is a structured precheck result rather than a transport error.

func (*Client) HasToken added in v0.3.0

func (c *Client) HasToken() bool

HasToken reports whether the client can perform authenticated write actions.

func (*Client) Precheck added in v0.3.0

func (c *Client) Precheck(ctx context.Context, match string, draft ConfigRulesRequest) (*PrecheckResponse, error)

Precheck validates exactly the supplied draft. HTTP 422 is a successful protocol response carrying validation findings, not a transport error.

func (*Client) Reload added in v0.3.0

func (c *Client) Reload(ctx context.Context) (*ReloadResponse, error)

Reload reloads the daemon configuration from disk.

func (*Client) Rules added in v0.3.0

func (c *Client) Rules(ctx context.Context) (*RulesResponse, error)

func (*Client) Session added in v0.3.0

func (c *Client) Session(ctx context.Context) (*SessionResponse, error)

func (*Client) SetHTTPClient added in v0.3.0

func (c *Client) SetHTTPClient(h *http.Client)

SetHTTPClient replaces the HTTP client used for management requests. Pass nil to keep the default; otherwise the caller controls TLS and timeouts.

func (*Client) SetHeaders added in v0.3.0

func (c *Client) SetHeaders(h http.Header)

SetHeaders sets extra headers applied to every request. nil clears them.

func (*Client) StartBot added in v0.3.0

func (c *Client) StartBot(ctx context.Context) error

StartBot starts the bot using the current persisted configuration.

func (*Client) Stats added in v0.3.0

func (c *Client) Stats(ctx context.Context) (*StatsResponse, error)

func (*Client) StopBot added in v0.3.0

func (c *Client) StopBot(ctx context.Context) error

StopBot stops the running bot without changing persisted configuration.

type ClientTLSFlags added in v0.3.0

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

ClientTLSFlags holds the standard control-API client TLS flags registered on a *flag.FlagSet. Call Opts() after parsing to get a ClientTLSOptions.

func AddClientTLSFlags added in v0.3.0

func AddClientTLSFlags(fs *flag.FlagSet) *ClientTLSFlags

AddClientTLSFlags registers the standard control-API client TLS flags on fs (use flag.CommandLine for the legacy relay* binaries) and returns a handle. Each flag falls back to its VMFLOW_TLS_* environment variable.

func (*ClientTLSFlags) Opts added in v0.3.0

func (f *ClientTLSFlags) Opts() ClientTLSOptions

Opts returns the parsed client TLS options.

type ClientTLSOptions added in v0.3.0

type ClientTLSOptions struct {
	CAFile             string // CA bundle to verify the server certificate (for private/self-signed CAs)
	ClientCertFile     string // client certificate (required for mTLS when the server sets client_ca_file)
	ClientKeyFile      string // client key (required together with ClientCertFile)
	InsecureSkipVerify bool   // skip server certificate verification (debug only)
}

ClientTLSOptions configures TLS for a control API client (vmflow ctl/tui).

func (ClientTLSOptions) Any added in v0.3.0

func (o ClientTLSOptions) Any() bool

Any reports whether any TLS option is set.

type ConfigRuleDiff added in v0.3.0

type ConfigRuleDiff struct {
	RuleID        string `json:"rule_id"`
	ConfigAction  string `json:"config_action"`
	RuntimeAction string `json:"runtime_action"`
}

type ConfigRulesRequest added in v0.3.0

type ConfigRulesRequest struct {
	UDPMaxSessions int           `json:"udp_max_sessions"`
	Rules          []engine.Rule `json:"rules"`
}

ConfigRulesRequest is the PUT /v1/config/rules body.

type ConfigRulesResponse added in v0.3.0

type ConfigRulesResponse struct {
	Revision       string        `json:"revision"`
	Writable       bool          `json:"writable"`
	UDPMaxSessions int           `json:"udp_max_sessions"`
	Rules          []engine.Rule `json:"rules"`
	ETag           string        `json:"-"`
}

ConfigRulesResponse is the GET /v1/config/rules payload. ETag is populated from the response ETag header (or the revision) for optimistic concurrency.

type CurrentPrecheckResponse added in v0.3.0

type CurrentPrecheckResponse struct {
	ConfigPath string          `json:"config_path,omitempty"`
	RuleCount  int             `json:"rule_count,omitempty"`
	Error      string          `json:"error,omitempty"`
	Result     precheck.Result `json:"result"`
}

CurrentPrecheckResponse is the GET /v1/precheck payload for the daemon's current on-disk configuration. A non-empty Error reports a configuration load failure; Result still contains the corresponding structured finding.

type HeaderFlags added in v0.3.0

type HeaderFlags []string

HeaderFlags is a repeatable -H/--header flag. Each entry is "Name: Value" or "Name=Value" (curl-style). It is seeded from the VMFLOW_HEADERS environment variable (semicolon-separated) so service tokens etc. can be supplied without putting secrets on the command line.

func AddHeaderFlags added in v0.3.0

func AddHeaderFlags(fs *flag.FlagSet) *HeaderFlags

AddHeaderFlags registers -H and --header on fs, seeded from VMFLOW_HEADERS (semicolon-separated "Name: Value"). Returns the handle.

func (HeaderFlags) Any added in v0.3.0

func (h HeaderFlags) Any() bool

Any reports whether any header is configured.

func (HeaderFlags) Apply added in v0.3.0

func (h HeaderFlags) Apply(req *http.Request)

Apply sets the configured headers on req (later entries win per name).

func (HeaderFlags) HTTPHeader added in v0.3.0

func (h HeaderFlags) HTTPHeader() http.Header

HTTPHeader returns the configured headers as an http.Header.

func (*HeaderFlags) Set added in v0.3.0

func (h *HeaderFlags) Set(s string) error

func (*HeaderFlags) String added in v0.3.0

func (h *HeaderFlags) String() string

type PrecheckResponse added in v0.3.0

type PrecheckResponse struct {
	Revision              string           `json:"revision"`
	UDPMaxSessionsChanged bool             `json:"udp_max_sessions_changed"`
	Diff                  []ConfigRuleDiff `json:"diff"`
	Precheck              precheck.Result  `json:"precheck"`
}

type ReloadApplyError added in v0.3.0

type ReloadApplyError struct {
	Transaction engine.TransactionalApplyResult `json:"transaction"`
}

func (*ReloadApplyError) Error added in v0.3.0

func (err *ReloadApplyError) Error() string

type ReloadResponse added in v0.3.0

type ReloadResponse struct {
	ConfigPath  string `json:"config_path"`
	ControlPort int    `json:"control_port"`
	RuleCount   int    `json:"rule_count"`
}

type RestartRequiredError added in v0.3.0

type RestartRequiredError struct {
	Fields []string `json:"fields"`
}

RestartRequiredError reports configuration fields that cannot be changed by hot reload without leaving the API response out of sync with the daemon.

func (*RestartRequiredError) Error added in v0.3.0

func (err *RestartRequiredError) Error() string

type RulesResponse added in v0.3.0

type RulesResponse struct {
	Items []engine.Rule `json:"items"`
}

RulesResponse is the legacy runtime-only rule endpoint. ConfigRulesResponse is the source of truth for management because it also contains disabled rules.

type Runtime

type Runtime struct {
	ConfigPath      string
	ServerVersion   string
	Commit          string
	StartedAt       time.Time
	Manager         *engine.Manager
	Logger          *slog.Logger
	Auth            *Authenticator
	Metrics         *metrics.Collector
	PrecheckOptions *precheck.Options
	CertStore       *certstore.Store
	CertReviewer    *certreview.Reviewer
	// HostNetwork returns a snapshot of the daemon host. It is optional so
	// embedders can omit host-level inspection from their control surface.
	HostNetwork func(context.Context) (netinfo.Snapshot, error)
	// Bot controls the Telegram bot lifecycle at runtime. May be nil when bot
	// support is disabled; bot config endpoints report unavailable then.
	Bot BotController
	// StartupConfig is the normalized file configuration used to start the
	// daemon. Reload uses it to reject changes to restart-only fields.
	StartupConfig *config.File
	// contains filtered or unexported fields
}

func (*Runtime) Precheck

func (runtime *Runtime) Precheck() (config.File, precheck.Result, error)

func (*Runtime) Reload

func (runtime *Runtime) Reload() (config.File, engine.ApplyResult, error)

type SessionCapabilities added in v0.3.0

type SessionCapabilities struct {
	RulesWrite bool `json:"rules_write"`
}

type SessionResponse added in v0.3.0

type SessionResponse struct {
	Actor         string              `json:"actor"`
	Role          string              `json:"role"`
	Capabilities  SessionCapabilities `json:"capabilities"`
	APIVersion    string              `json:"api_version,omitempty"`
	ServerVersion string              `json:"server_version,omitempty"`
	Commit        string              `json:"commit,omitempty"`
	StartedTime   int64               `json:"started_time,omitempty"`
	Degraded      bool                `json:"degraded"`
	DegradedCause string              `json:"degraded_cause,omitempty"`
}

type SetupConfigUpdate added in v0.3.0

type SetupConfigUpdate struct {
	Language         string
	Auth             config.AuthConfig
	Rules            []engine.Rule
	RulesHeadComment string
}

SetupConfigUpdate is the configuration surface owned by the first-run workflow. Existing files retain every other top-level field and unknown YAML node.

type StatsResponse added in v0.3.0

type StatsResponse struct {
	Items       []TrafficSnapshot `json:"items"`
	HostNetwork *netinfo.Snapshot `json:"host_network,omitempty"`
}

type TrafficSnapshot added in v0.3.0

type TrafficSnapshot = engine.TrafficSnapshot

Jump to

Keyboard shortcuts

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