tenancy

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 9, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package tenancy implements VORTEX's multi-tenancy layer (build plan M8): namespaces that isolate routes, secrets, metrics, and logs per tenant, with per-namespace resource quotas enforced at the HTTP and TCP edge. Standard library only.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAlreadyExists = errors.New("tenancy: namespace already exists")
	ErrNotFound      = errors.New("tenancy: namespace not found")
)

Registry errors.

View Source
var ErrQuotaExceeded = errors.New("tenancy: quota exceeded")

ErrQuotaExceeded is returned by CheckQuota when a resource is over its limit.

Functions

func NamespaceIDFromContext

func NamespaceIDFromContext(ctx context.Context) string

NamespaceIDFromContext returns the namespace ID in ctx, or "".

func WithNamespace

func WithNamespace(ctx context.Context, ns *Namespace) context.Context

WithNamespace returns a copy of ctx carrying ns.

Types

type Enforcer

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

Enforcer enforces namespace quotas at the HTTP and TCP layers. It is safe for concurrent use.

func NewEnforcer

func NewEnforcer(registry *Registry) *Enforcer

NewEnforcer builds an Enforcer backed by registry. It starts a background goroutine that resets bandwidth counters once per window.

func (*Enforcer) HTTPMiddleware

func (e *Enforcer) HTTPMiddleware(namespaceID string) func(http.Handler) http.Handler

HTTPMiddleware returns a middleware that enforces the connection quota for namespaceID: it increments the active-connection counter for the duration of each request and rejects with 429 when the limit is reached.

func (*Enforcer) RecordBandwidth

func (e *Enforcer) RecordBandwidth(namespaceID string, bytes int64)

RecordBandwidth adds bytes to a namespace's current-window bandwidth counter.

func (*Enforcer) SetRouteCount

func (e *Enforcer) SetRouteCount(namespaceID string, n int)

SetRouteCount records the number of routes assigned to a namespace.

func (*Enforcer) Stats

func (e *Enforcer) Stats(namespaceID string) QuotaStats

Stats returns a snapshot of a namespace's usage.

func (*Enforcer) TCPMiddleware

func (e *Enforcer) TCPMiddleware(namespaceID string) func(net.Conn) (net.Conn, error)

TCPMiddleware returns a connection wrapper enforcing MaxConnections for a namespace. It returns an error (closing the connection) when the limit is reached; otherwise it returns a wrapped conn that decrements the counter on Close.

type IsolatedMetrics

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

IsolatedMetrics wraps observability.Metrics, prefixing the route label with the namespace ID so each namespace's metrics are attributable to it.

func NewIsolatedMetrics

func NewIsolatedMetrics(metrics *observability.Metrics, nsID string) *IsolatedMetrics

NewIsolatedMetrics wraps metrics for namespace nsID.

func (*IsolatedMetrics) RecordBytes

func (m *IsolatedMetrics) RecordBytes(route string, in, out int64)

RecordBytes records bytes under the namespaced label.

func (*IsolatedMetrics) RecordRequest

func (m *IsolatedMetrics) RecordRequest(route, method string, status int, dur time.Duration)

RecordRequest records a request under the namespaced route label.

func (*IsolatedMetrics) SetActiveConns

func (m *IsolatedMetrics) SetActiveConns(route, protocol string, n int64)

SetActiveConns sets the active-connection gauge under the namespaced label.

type IsolatedSecretStore

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

IsolatedSecretStore wraps a SecretStore, prefixing every key with a sanitized namespace ID so secrets in different namespaces never collide and one namespace cannot read another's secrets.

func NewIsolatedSecretStore

func NewIsolatedSecretStore(store *secrets.SecretStore, nsID string) *IsolatedSecretStore

NewIsolatedSecretStore wraps store for namespace nsID.

func (*IsolatedSecretStore) Delete

func (s *IsolatedSecretStore) Delete(name string) error

Delete removes the namespace-prefixed key.

func (*IsolatedSecretStore) Exists

func (s *IsolatedSecretStore) Exists(name string) (bool, error)

Exists reports whether the namespace-prefixed key is set.

func (*IsolatedSecretStore) Get

func (s *IsolatedSecretStore) Get(name string) (string, error)

Get retrieves the namespace-prefixed key.

func (*IsolatedSecretStore) List

func (s *IsolatedSecretStore) List() ([]string, error)

List returns this namespace's secret names with the prefix stripped, so a namespace sees only its own keys.

func (*IsolatedSecretStore) Set

func (s *IsolatedSecretStore) Set(name, value string) error

Set stores value under the namespace-prefixed key.

type Namespace

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

Namespace is a tenant isolation boundary with quotas. It is immutable after creation except via the Registry's Update.

func NamespaceFromContext

func NamespaceFromContext(ctx context.Context) (*Namespace, bool)

NamespaceFromContext returns the namespace stored in ctx, if any.

func NewNamespace

func NewNamespace(cfg NamespaceConfig) (*Namespace, error)

NewNamespace validates cfg and constructs a Namespace. ID and OrgID are required; ID must be alphanumeric and hyphens only.

func (*Namespace) CheckQuota

func (n *Namespace) CheckQuota(resource string, current int64) error

CheckQuota reports whether current usage of resource is within quota. A zero limit means unlimited (always nil). It returns an error wrapping ErrQuotaExceeded (naming the resource and limit) when over.

resource is one of: "routes", "secrets", "connections", "bandwidth".

func (*Namespace) Config

func (n *Namespace) Config() NamespaceConfig

Config returns a copy of the namespace's full config.

func (*Namespace) ID

func (n *Namespace) ID() string

ID returns the namespace identifier.

func (*Namespace) Name

func (n *Namespace) Name() string

Name returns the human-readable namespace name.

func (*Namespace) OrgID

func (n *Namespace) OrgID() string

OrgID returns the owning organization ID.

func (*Namespace) Quotas

func (n *Namespace) Quotas() QuotaConfig

Quotas returns the namespace's quota configuration.

type NamespaceConfig

type NamespaceConfig struct {
	ID     string      `json:"id"`
	Name   string      `json:"name"`
	OrgID  string      `json:"org_id"`
	Quotas QuotaConfig `json:"quotas"`
}

NamespaceConfig describes a tenant namespace.

type QuotaConfig

type QuotaConfig struct {
	MaxRoutes      int   `json:"max_routes"`
	MaxSecrets     int   `json:"max_secrets"`
	MaxConnections int64 `json:"max_connections"`
	BandwidthMbps  int64 `json:"bandwidth_mbps"` // 0 = unlimited
	MaxAgents      int   `json:"max_agents"`     // reserved for the agent system
}

QuotaConfig bounds a namespace's resource use. A zero limit means unlimited.

type QuotaStats

type QuotaStats struct {
	ActiveConns   int64
	BandwidthUsed int64 // bytes in the current window
	RouteCount    int
}

QuotaStats is a snapshot of a namespace's live resource usage.

type Registry

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

Registry holds all namespaces, keyed by ID. It is safe for concurrent use.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty registry.

func (*Registry) Create

func (r *Registry) Create(cfg NamespaceConfig) (*Namespace, error)

Create validates and stores a new namespace. It returns ErrAlreadyExists if the ID is taken.

func (*Registry) Delete

func (r *Registry) Delete(id string) error

Delete removes the namespace with id, or ErrNotFound.

func (*Registry) Get

func (r *Registry) Get(id string) (*Namespace, error)

Get returns the namespace with id, or ErrNotFound.

func (*Registry) List

func (r *Registry) List(orgID string) []*Namespace

List returns all namespaces for orgID. An empty orgID returns every namespace.

func (*Registry) Load

func (r *Registry) Load(path string) error

Load replaces the registry contents with the namespaces in the JSON file at path. A missing file is treated as an empty registry (not an error).

func (*Registry) Save

func (r *Registry) Save(path string) error

Save persists the registry to path as a JSON array of namespace configs.

func (*Registry) Update

func (r *Registry) Update(id string, cfg NamespaceConfig) error

Update changes a namespace's name and quotas. The ID and OrgID are immutable: cfg.ID must match id, and cfg.OrgID must match the existing OrgID.

Jump to

Keyboard shortcuts

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