realm

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package realm is the Realm Management API (docs/DESIGN.md §3.7, ROADMAP §8.1 files 7.1–7.2): the operator-facing surface for installing and versioning interfaces, managing triggers, and rotating a realm's JWT auth key. It is wire-shaped to upstream astarte_realm_management so astartectl and the dashboard work unmodified, and every mutation both emits the store NOTIFY and calls the in-process engine invalidation callback so changes take effect immediately.

Index

Constants

View Source
const APICompatVersion = "1.2.2"

APICompatVersion is the upstream Realm Management API level Astrate emulates, reported by GET /v1/{realm}/version. The Astarte Dashboard feature-gates UI sections on it (the Trigger Delivery Policies page requires >= 1.1.1), so this is a compatibility declaration, not Astrate's own release version (docs/COMPATIBILITY.md). Bump rule: only in the same change that completes the full surface of the new level, after reconciling every row in docs/UPSTREAM-EXPERIMENTAL.md tagged with it — never via configuration, never speculatively.

Variables

View Source
var (
	// ErrNameMismatch is a PUT whose body interface_name disagrees with the
	// URL (upstream name_not_matching, #62).
	ErrNameMismatch = errors.New("realm: interface name does not match")
	// ErrMajorMismatch is a PUT whose body version_major disagrees with the
	// URL (upstream major_version_not_matching, #62).
	ErrMajorMismatch = errors.New("realm: interface major does not match")
	// ErrNameCollision rejects an install whose name equals an installed one
	// modulo case and hyphens (upstream interface_name_collision, #62).
	ErrNameCollision = errors.New("realm: interface name collision")
)
View Source
var ErrMaximumDatabaseRetentionExceeded = errors.New("realm: maximum_database_retention_exceeded")

ErrMaximumDatabaseRetentionExceeded rejects an interface install/update whose mapping TTL exceeds the realm's datastream_maximum_storage_retention ceiling (upstream error_name maximum_database_retention_exceeded, #72).

View Source
var ErrValidation = errors.New("realm: validation failed")

ErrValidation wraps a request that is well-formed JSON but violates an interface/trigger schema rule (maps to a 422). Use errors.Is against it and fmt.Errorf("%w: ...", ErrValidation, ...) to attach the detail.

Functions

This section is empty.

Types

type API

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

API is the /realmmanagement/v1 HTTP surface (docs/ROADMAP.md §8.1 file 7.2). Every route is guarded by a realm JWT carrying a_rma.

func NewAPI

func NewAPI(svc *Service, mw *auth.Middleware) *API

NewAPI wires the realm service to its HTTP surface. mw provides the realm-JWT middleware (M3).

func (*API) Mount

func (a *API) Mount(mux *http.ServeMux)

Mount registers the routes on mux (paths wire-frozen to upstream astarte_realm_management).

type Disconnecter added in v0.2.0

type Disconnecter interface {
	DisconnectDevice(realm string, id deviceid.ID)
}

Disconnecter force-closes a device's live MQTT session (*broker.Broker satisfies it). Device deletion kicks the session before wiping the rows, mirroring upstream's disconnect-first deletion order. A nil Disconnecter skips the kick; the deleted device is then refused at its next reconnect or credential request instead.

type Invalidator

type Invalidator interface {
	RefreshInterfaces(ctx context.Context, realmID int16) error
	RefreshTriggers(ctx context.Context, realmID int16) error
}

Invalidator is the in-process cache-invalidation callback the engine satisfies (*engine.Engine's RefreshInterfaces / RefreshTriggers). After a realm mutation the service refreshes the engine's compiled snapshot so the change takes effect without waiting for the LISTEN/NOTIFY round-trip. A nil Invalidator disables the in-process path; the store NOTIFY still fires.

type OnDeletionFunc added in v0.2.0

type OnDeletionFunc func(realmName, deviceID string, at time.Time)

OnDeletionFunc is called around a synchronous device delete so the engine can emit device_deletion_started / device_deletion_finished (issue #21). The callback receives the realm name, encoded device ID, and the instant.

type Service

type Service struct {

	// OnDeletionStart / OnDeletionFinish bookend DeleteDevice (nil-safe).
	OnDeletionStart  OnDeletionFunc
	OnDeletionFinish OnDeletionFunc
	// contains filtered or unexported fields
}

Service implements the Realm Management business logic over the store.

func NewService

func NewService(st *store.Store, inv Invalidator, log *slog.Logger) *Service

NewService builds the service. inv may be nil (e.g. management-only deployments without a local engine); log defaults to slog.Default().

func (*Service) CreatePolicy added in v0.2.0

func (s *Service) CreatePolicy(ctx context.Context, realm string, def []byte) (*store.TriggerPolicy, error)

CreatePolicy validates and stores a delivery policy (upstream POST /policies). Duplicates yield store.ErrAlreadyExists.

func (*Service) CreateTrigger

func (s *Service) CreateTrigger(ctx context.Context, realm string, def []byte) (*store.Trigger, error)

CreateTrigger validates a trigger definition (name + action + simple triggers, via triggers.Compile — the same validation the engine applies) and installs it. A duplicate name yields store.ErrAlreadyExists. If the trigger references a policy, that policy must already exist in the realm; otherwise the request is rejected as a validation error.

func (*Service) DeleteDevice added in v0.2.0

func (s *Service) DeleteDevice(ctx context.Context, realm, deviceID string) error

DeleteDevice synchronously removes a device and all its data (upstream starts an async deletion with a transient deletion_in_progress state; Astrate is single-process and deletes in one transaction — docs/COMPATIBILITY.md). Emits device_deletion_started immediately before the store delete and device_deletion_finished immediately after (issue #21: back-to-back around the sync path so imported trigger configs still fire). finished is emitted even when the store delete fails, so a started lifecycle always closes.

func (*Service) DeleteInterface

func (s *Service) DeleteInterface(ctx context.Context, realm, name string, major int) error

DeleteInterface removes an interface major. The store enforces the upstream draining rules (store.ErrInterfaceMajorNotZero, store.ErrInterfaceInUse); a lookup miss is marked errMajorNotFound for the HTTP layer (#62).

func (*Service) DeletePolicy added in v0.2.0

func (s *Service) DeletePolicy(ctx context.Context, realm, name string) error

DeletePolicy removes a policy. The request is rejected if any trigger in the realm still references this policy.

func (*Service) DeleteTrigger

func (s *Service) DeleteTrigger(ctx context.Context, realm, name string) error

DeleteTrigger removes one trigger by name.

func (*Service) GetAuthKey

func (s *Service) GetAuthKey(ctx context.Context, realm string) (string, error)

GetAuthKey returns the realm's JWT public key PEM (upstream GET /config/auth → {"jwt_public_key_pem": "..."}). Astrate stores a list for rotation; the wire field carries them concatenated, which the verifier already splits into individual keys.

func (*Service) GetDatastreamMaximumStorageRetention added in v0.2.0

func (s *Service) GetDatastreamMaximumStorageRetention(ctx context.Context, realm string) (int64, error)

GetDatastreamMaximumStorageRetention returns the realm's datastream maximum storage retention in seconds, upstream GET /config/datastream_maximum_storage_retention (served since 1.2.0). An unset ceiling renders as 0 — the #60 wire contract (upstream answers null here, a recorded deviation), pinned by tests.

func (*Service) GetDeviceRegistrationLimit added in v0.2.0

func (s *Service) GetDeviceRegistrationLimit(ctx context.Context, realm string) (*int32, error)

GetDeviceRegistrationLimit returns the realm's device registration limit (nil = unlimited), upstream GET /config/device_registration_limit.

func (*Service) GetInterface

func (s *Service) GetInterface(ctx context.Context, realm, name string, major int) (json.RawMessage, error)

GetInterface returns the stored definition JSON of one interface major (upstream GET /interfaces/{name}/{major}).

func (*Service) GetPolicy added in v0.2.0

func (s *Service) GetPolicy(ctx context.Context, realm, name string) (json.RawMessage, error)

GetPolicy returns one policy's definition.

func (*Service) GetTrigger

func (s *Service) GetTrigger(ctx context.Context, realm, name string) (json.RawMessage, error)

GetTrigger returns one trigger's definition JSON.

func (*Service) InstallInterface

func (s *Service) InstallInterface(ctx context.Context, realm string, def []byte) (*store.StoredInterface, error)

InstallInterface validates and installs a new interface major (docs/ROADMAP.md §8.1). A duplicate (name, major) yields store.ErrAlreadyExists; a schema violation yields ErrValidation — carrying a *interfaceschema.ViolationsError when the rejection has a probe-verified upstream wire shape (#61). Documents posted with legacy alias fields (quality/aggregate/path) are stored canonically so GET renders them the way upstream does.

func (*Service) ListInterfaceMajors

func (s *Service) ListInterfaceMajors(ctx context.Context, realm, name string) ([]int, error)

ListInterfaceMajors returns the installed major versions of one interface name (upstream GET /interfaces/{name}), ascending. An unknown name yields store.ErrNotFound.

func (*Service) ListInterfaces

func (s *Service) ListInterfaces(ctx context.Context, realm string) ([]string, error)

ListInterfaces returns the distinct interface names installed in the realm (upstream GET /interfaces), sorted for stable output.

func (*Service) ListInterfacesDetailed added in v0.2.0

func (s *Service) ListInterfacesDetailed(ctx context.Context, realm string) ([]json.RawMessage, error)

ListInterfacesDetailed renders the additive 1.4-style detailed listing (issue #66): one fully materialised document per installed interface major, sorted by (name, major). The names-only listing upstream 1.2 serves stays on ListInterfaces.

func (*Service) ListPolicies added in v0.2.0

func (s *Service) ListPolicies(ctx context.Context, realm string) ([]string, error)

ListPolicies returns the realm's policy names.

func (*Service) ListTriggers

func (s *Service) ListTriggers(ctx context.Context, realm string) ([]string, error)

ListTriggers returns the realm's trigger names, sorted.

func (*Service) SetAuthKey

func (s *Service) SetAuthKey(ctx context.Context, realm, keyPEM string) error

SetAuthKey rotates the realm's JWT public key (upstream PUT /config/auth). The supplied PEM may concatenate multiple keys for a rotation window.

func (*Service) UpdateInterface

func (s *Service) UpdateInterface(ctx context.Context, realm, urlName string, urlMajor int, def []byte) (*store.StoredInterface, error)

UpdateInterface applies a minor upgrade, enforcing the additive-only upstream parity rules via interfaceschema.CheckMinorUpgrade (no mutated mapping attributes, same type/ownership/aggregation, strictly higher minor). urlName/urlMajor are the interface identity from the URL path: the parsed body must agree with both (upstream 409s the mismatches, #62), and a lookup miss on that identity yields the "major not found" marker.

func (*Service) WithDisconnecter added in v0.2.0

func (s *Service) WithDisconnecter(d Disconnecter) *Service

WithDisconnecter attaches the broker seam used to kick a live session at device deletion (nil-safe, mirrors housekeeping's Reloader wiring).

Jump to

Keyboard shortcuts

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