rules

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package rules implements pano's live traffic rules and breakpoints. An Engine satisfies proxy.Hooks: the proxy calls Request before contacting the origin and Response once response headers are known, and the engine matches the exchange against its rule set and applies the matching rules' actions.

Rules

A rule (api.Rule) is a Match plus an ordered list of Actions. Rules are evaluated in priority order (higher first, then oldest first). Every field set on the Match must hold for the rule to fire:

  • Host is a glob (internal/glob) matched against the flow host; a pattern containing ':' is matched against host:port instead.
  • Path is a prefix ("/v1/"), a glob ("/v1/*/models"), or a regexp when wrapped in slashes and the inner text uses regexp syntax ("/^\/v[12]\//").
  • Method is a case-insensitive list, Scheme is "http" or "https".
  • Header maps a header name to a glob matched against the joined request header value; an empty glob only requires the header to be present.
  • Status is a response-phase spec: "500", "4xx", "400-499", "!2xx", "200|204".
  • Phase is request, response or both. When empty it is derived from the actions: a rule whose actions all run on the response side is a response rule, otherwise it is a request rule (or a response rule when Status is set).

Actions run in order. Each applied action appends a flow.RuleHit to the flow. mock, block and breakpoint (drop) end the evaluation. Action types:

delay          sleep ms (+ random jitter_ms), cancelled with the request
set_header     set name: value on the request or response
remove_header  delete name
set_query      set name=value on the request URL
rewrite_body   json_patch (dotted paths -> values), regex + replace, or a
               text/template with .Host .Path .Method .Status .Body and
               .Header "Name"; gzip bodies are decoded and served plain
mock           answer with status/headers/body without contacting the origin
mock_every_n   like mock but only on every nth hit (value = n)
block          mode reset (drop the connection), timeout (hang for ms),
               or status (default: answer with status, default 502)
redirect       send the request to upstream ("http://localhost:3000")
throttle       limit the response body to kbps kilobytes per second
breakpoint     park the exchange until Resume (alias: hold)
tag            add tags to the flow

mock, mock_every_n, block, redirect and set_query default to the request side; throttle is response only; the rest apply in whichever phase the rule is evaluated unless On pins them. Probability gates the whole rule, MaxHits disables it once reached and TTLSeconds/Expires remove it lazily.

Breakpoints

A breakpoint sets the flow to flow.StateHeld, publishes flow.EvHeld and blocks the exchange until Resume is called, the client goes away, or Options.HoldTimeout elapses. Resume may edit the parked request (URL, method, headers, body) or response (status, headers, body) before it continues, or drop it.

Concurrency and persistence

The compiled rule set lives behind an atomic pointer and is replaced on every change, so the hot path is lock-free and allocates nothing for rules that do not match. Changes are written atomically to Options.PersistPath as a JSON array of api.Rule.

Index

Constants

View Source
const (
	ActionDelay        = "delay"
	ActionSetHeader    = "set_header"
	ActionRemoveHeader = "remove_header"
	ActionSetQuery     = "set_query"
	ActionRewriteBody  = "rewrite_body"
	ActionMock         = "mock"
	ActionMockEveryN   = "mock_every_n"
	ActionBlock        = "block"
	ActionRedirect     = "redirect"
	ActionThrottle     = "throttle"
	ActionBreakpoint   = "breakpoint"
	ActionTag          = "tag"
)

Action types accepted in api.Action.Type.

View Source
const DefaultHoldTimeout = 120 * time.Second

DefaultHoldTimeout is how long a breakpoint parks an exchange before it auto-continues when Options.HoldTimeout is zero.

View Source
const MaxBodyBytes = 8 << 20

MaxBodyBytes bounds the body size the engine buffers to rewrite or hold an exchange. Larger bodies pass through untouched and the RuleHit says so.

Variables

View Source
var (
	// ErrNotFound is returned for unknown rule ids and held flow ids.
	ErrNotFound = errors.New("rules: not found")
	// ErrConflict is returned when adding a rule whose id already exists.
	ErrConflict = errors.New("rules: id already exists")
	// ErrInvalid is matched (errors.Is) by every validation failure.
	ErrInvalid = errors.New("rules: invalid")
)

Functions

This section is empty.

Types

type Engine

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

Engine holds the rule set and the breakpoint registry. It implements proxy.Hooks. Mutations take a mutex; the hot path is lock-free.

func New

func New(opts Options) (*Engine, error)

New creates an engine, loading PersistPath when it exists. Rules whose expiry has passed are dropped at load; rules that no longer validate are skipped with a warning.

func (*Engine) Add

func (e *Engine) Add(req api.RuleAddRequest) (api.Rule, error)

Add creates a rule from req.Rule or from req.Preset and req.Params. Name and TTLS on the request override the rule's own. The returned rule is the normalised form with ID, CreatedAt, Enabled and Hits filled.

func (*Engine) Close

func (e *Engine) Close() error

Close releases every held exchange (they continue unmodified) and persists the final hit counters.

func (*Engine) Get

func (e *Engine) Get(id string) (api.Rule, bool)

Get returns one rule.

func (*Engine) Held

func (e *Engine) Held() []api.Held

Held lists the parked exchanges, oldest first.

func (*Engine) List

func (e *Engine) List() []api.Rule

List returns every rule, in evaluation order.

func (*Engine) Presets

func (e *Engine) Presets() []PresetInfo

Presets lists the available presets with their parameters and defaults.

func (*Engine) Remove

func (e *Engine) Remove(id string) error

Remove deletes a rule.

func (*Engine) RemoveAll

func (e *Engine) RemoveAll() int

RemoveAll deletes every rule and returns how many were removed.

func (*Engine) Request

func (e *Engine) Request(ctx context.Context, f *flow.Flow, r *http.Request) proxy.Decision

Request implements proxy.Hooks. It runs the request-phase actions of every matching rule in order and stops at the first mock or block.

func (*Engine) Response

func (e *Engine) Response(ctx context.Context, f *flow.Flow, r *http.Request, resp *http.Response) proxy.Decision

Response implements proxy.Hooks for the response phase.

func (*Engine) Resume

func (e *Engine) Resume(id flow.ID, req api.ResumeRequest) error

Resume releases a held exchange. Action "resume" (or empty) continues it with the given edits applied; "drop" resets the connection. Request-phase edits: URL, Method, SetHeaders, RemoveHeaders, Body, BodyPatch. Response-phase edits: Status, SetHeaders, RemoveHeaders, Body, BodyPatch.

func (*Engine) Update

func (e *Engine) Update(id string, p api.RulePatch) (api.Rule, error)

Update patches a rule. A non-nil p.Rule replaces the match, actions and limits wholesale (ID, CreatedAt and Hits are kept); p.Name and p.Enabled take precedence over the fields inside p.Rule. Re-enabling a rule that was disabled by MaxHits resets its hit counter.

func (*Engine) Version

func (e *Engine) Version() uint64

Version is a counter that increases on every change to the rule set (including hit-limit disables and lazy expiry).

type Options

type Options struct {
	// PersistPath is the rules.json file written on every change and loaded
	// by New. Empty disables persistence.
	PersistPath string
	// HoldTimeout bounds how long a breakpoint parks an exchange before it
	// continues on its own. Zero means DefaultHoldTimeout.
	HoldTimeout time.Duration
	// Publish, if set, receives a flow.EvHeld event whenever a breakpoint
	// parks a flow (typically bus.Publish).
	Publish func(flow.Event)
	// Logger receives warnings about persistence and skipped rules. Nil means
	// slog.Default().
	Logger *slog.Logger
	// Now overrides the clock used for timestamps and expiry (tests).
	Now func() time.Time
}

Options configure an Engine.

type PresetInfo

type PresetInfo struct {
	Name        string        `json:"name"`
	Description string        `json:"description"`
	Params      []PresetParam `json:"params"`
}

PresetInfo describes a rule preset.

type PresetParam

type PresetParam struct {
	Name        string `json:"name"`
	Type        string `json:"type"` // string|number
	Default     any    `json:"default,omitempty"`
	Required    bool   `json:"required,omitempty"`
	Description string `json:"description"`
}

PresetParam describes one preset parameter.

Jump to

Keyboard shortcuts

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