Documentation
¶
Overview ¶
Package namespaces owns the namespace control-plane state and exposes a typed domain API for callers that need direct existence checks. Lookups return the RAFT subcommand namespace type.
Index ¶
- Variables
- func PublicMessage(err error) (msg string, ok bool)
- func RequireActive(e Exister, name string) error
- func ValidateName(name string) error
- type Controller
- func (c *Controller) ChangeState(name string, target cmd.NamespaceState, sc StateChange) error
- func (c *Controller) Count() int
- func (c *Controller) Create(ns cmd.Namespace, index uint64) error
- func (c *Controller) Get(names ...string) []cmd.Namespace
- func (c *Controller) GetNamespace(name string) (ns cmd.Namespace, ok bool)
- func (c *Controller) List() []cmd.Namespace
- func (c *Controller) ListDeleting() []string
- func (c *Controller) RemoveEntity(name string) error
- func (c *Controller) Restore(snapshot []byte) error
- func (c *Controller) Snapshot() ([]byte, error)
- func (c *Controller) Update(ns cmd.Namespace) error
- type Exister
- type MockExister
- type MockExister_Expecter
- type MockExister_GetNamespace_Call
- func (_c *MockExister_GetNamespace_Call) Return(_a0 api.Namespace, _a1 bool) *MockExister_GetNamespace_Call
- func (_c *MockExister_GetNamespace_Call) Run(run func(name string)) *MockExister_GetNamespace_Call
- func (_c *MockExister_GetNamespace_Call) RunAndReturn(run func(string) (api.Namespace, bool)) *MockExister_GetNamespace_Call
- type StateChange
Constants ¶
This section is empty.
Variables ¶
var ( // ErrBadRequest signals a malformed RAFT command payload or an invalid // argument so the apply path can classify it distinctly from // legitimate-but-rejected operations. ErrBadRequest = errors.New("bad request") // ErrAlreadyExists is returned by Create when a namespace with the given // name is already present. Callers that need a distinct status for // duplicates (e.g. an HTTP handler mapping to 409) should check with // errors.Is rather than string-matching the error message. ErrAlreadyExists = errors.New("namespace already exists") // ErrNotFound is returned by ChangeState and RemoveEntity when the // target namespace does not exist. Callers that need a distinct status // for missing entries (e.g. an HTTP handler mapping to 404) should // check with errors.Is. ErrNotFound = errors.New("namespace not found") // ErrNamespaceDeleting is returned when a create-like operation targets // a namespace that exists but is currently being torn down. Distinct // from ErrAlreadyExists so REST can render a different conflict message. ErrNamespaceDeleting = errors.New("namespace is being deleted") // ErrNamespaceGone is returned by apply-time checks when a namespace // the caller validated earlier no longer exists. ErrNamespaceGone = errors.New("namespace no longer exists") // ErrNamespaceNotEmpty is returned by RemoveEntity at the apply layer // when the namespace still owns classes, aliases, or DB users. ErrNamespaceNotEmpty = errors.New("namespace still has owned resources") // ErrInvalidState is a defense-in-depth sentinel for operations called // on a namespace whose current state forbids them (e.g. RemoveEntity on // an active namespace). ErrInvalidState = errors.New("namespace is in an invalid state for this operation") // ErrInvalidStateTransition is returned by ChangeState when the target // state is unreachable from the namespace's current state. ErrInvalidStateTransition = errors.New("invalid namespace state transition") // ErrNamespaceSuspended is returned when an operation targets a suspended // namespace. ErrNamespaceSuspended = errors.New("namespace is suspended") // ErrCollectionSuspended is returned when an operation targets a suspended // collection. ErrCollectionSuspended = errors.New("collection is suspended") // ErrNamespaceResuming is returned when an operation targets a namespace // that is resuming. ErrNamespaceResuming = errors.New("namespace is resuming") // ErrStateChangedConcurrently is returned by ChangeState when the stored // StateChangeIndex no longer matches the one the caller read before // proposing, meaning another state change applied in between. Callers // re-read and decide again rather than retrying blindly. ErrStateChangedConcurrently = errors.New("namespace state changed concurrently") )
Functions ¶
func PublicMessage ¶ added in v1.38.6
PublicMessage returns the user-facing text for a namespace lifecycle sentinel. Every caller outside the namespace-management API must render this instead of err: it names neither the namespace nor the concept. ok is false for errors that are not lifecycle sentinels, so callers keep the detail of a genuine internal failure.
func RequireActive ¶ added in v1.38.6
RequireActive returns nil for an empty name or an active namespace, and the error for the namespace's actual state otherwise. Pass "" only for an entity that belongs to no namespace, never for one whose namespace is unknown.
func ValidateName ¶
ValidateName enforces the package's naming contract. It is the single source of truth for namespace name validation and is called both from the REST handler (for fast 422 rejection without a RAFT round-trip) and from the apply path (as a defense-in-depth check).
Types ¶
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller owns the namespace control-plane state.
Concurrency contract: hashicorp RAFT invokes Snapshot from a goroutine that may run concurrently with Apply, so the RLock inside Snapshot is load-bearing, not cosmetic. Applies are serialized by RAFT (write-lock semantics); queries take the read-lock. Do not remove the Snapshot RLock in a future refactor.
func NewController ¶
func NewController(logger logrus.FieldLogger) *Controller
NewController returns an empty, ready-to-use controller.
func (*Controller) ChangeState ¶
func (c *Controller) ChangeState(name string, target cmd.NamespaceState, sc StateChange) error
ChangeState transitions a namespace into target and records sc.AppliedIndex as the index of that flip. Same-state transitions are idempotent and leave the recorded index alone.
A nonzero sc.ExpectedIndex makes the flip conditional: refused with ErrStateChangedConcurrently unless the stored StateChangeIndex still matches, which stops a re-proposed command from undoing a later flip. It is checked after the same-state short-circuit, so re-applying a committed command still returns nil.
Returns ErrBadRequest when target is unknown or sc.AppliedIndex is 0, ErrNotFound for a missing namespace, and ErrInvalidStateTransition for a forbidden transition.
func (*Controller) Count ¶
func (c *Controller) Count() int
Count returns the number of known namespaces. Used by the startup invariant check.
func (*Controller) Create ¶
func (c *Controller) Create(ns cmd.Namespace, index uint64) error
Create inserts a namespace in the cmd.NamespaceStateActive state, recording index — the RAFT log index of the create command — as its StateChangeIndex. The input's State and StateChangeIndex are ignored, so a caller cannot choose either. HomeNodes must contain exactly one non-empty entry — downstream placement and counters rely on that invariant. Returns ErrBadRequest for invalid names, HomeNodes, or a zero index, ErrAlreadyExists when the name maps to an active namespace, and ErrNamespaceDeleting when the name is currently being torn down.
func (*Controller) Get ¶
func (c *Controller) Get(names ...string) []cmd.Namespace
Get returns the named namespaces. An empty Names slice returns all known namespaces; otherwise only the named ones that exist are returned (missing names are silently omitted).
func (*Controller) GetNamespace ¶
func (c *Controller) GetNamespace(name string) (ns cmd.Namespace, ok bool)
GetNamespace returns a snapshot copy of the namespace by name. ok is false when the namespace does not exist.
func (*Controller) List ¶
func (c *Controller) List() []cmd.Namespace
List returns a snapshot copy of all namespaces. Intended for callers that need to iterate without holding the lock.
func (*Controller) ListDeleting ¶
func (c *Controller) ListDeleting() []string
ListDeleting returns the names of namespaces currently in the deleting state, sorted lexicographically.
func (*Controller) RemoveEntity ¶
func (c *Controller) RemoveEntity(name string) error
RemoveEntity removes the namespace map entry. Callable only on a namespace already marked for deletion; an active namespace returns ErrInvalidState. Returns ErrNotFound when the namespace does not exist.
func (*Controller) Restore ¶
func (c *Controller) Restore(snapshot []byte) error
Restore replaces the current state with the snapshot contents. A nil or empty snapshot leaves state empty (fresh bootstrap). Unknown JSON fields are tolerated. Entries with empty State are normalized to cmd.NamespaceStateActive; entries with an unknown State return an error so a future binary's snapshot is not silently mis-classified. Entries missing the single HomeNodes entry are also rejected — there is no migration path from a pre-HomeNodes snapshot.
func (*Controller) Snapshot ¶
func (c *Controller) Snapshot() ([]byte, error)
Snapshot serializes the entire namespace map. See the Controller godoc for why the read lock is required even though Apply is single-threaded.
func (*Controller) Update ¶
func (c *Controller) Update(ns cmd.Namespace) error
Update overwrites the stored HomeNodes for an existing namespace. HomeNodes must contain exactly one non-empty entry; Name, State and StateChangeIndex are immutable here. Returns ErrBadRequest for an invalid HomeNodes, ErrNotFound when the namespace does not exist, and ErrNamespaceDeleting when the namespace is being torn down.
type Exister ¶
Exister exposes read-only access to namespace state. Callers that need to know whether a namespace is usable go through RequireActive rather than comparing State themselves.
type MockExister ¶
MockExister is an autogenerated mock type for the Exister type
func NewMockExister ¶
func NewMockExister(t interface {
mock.TestingT
Cleanup(func())
}) *MockExister
NewMockExister creates a new instance of MockExister. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. The first argument is typically a *testing.T value.
func (*MockExister) EXPECT ¶
func (_m *MockExister) EXPECT() *MockExister_Expecter
func (*MockExister) GetNamespace ¶
func (_m *MockExister) GetNamespace(name string) (api.Namespace, bool)
GetNamespace provides a mock function with given fields: name
type MockExister_Expecter ¶
type MockExister_Expecter struct {
// contains filtered or unexported fields
}
func (*MockExister_Expecter) GetNamespace ¶
func (_e *MockExister_Expecter) GetNamespace(name interface{}) *MockExister_GetNamespace_Call
GetNamespace is a helper method to define mock.On call
- name string
type MockExister_GetNamespace_Call ¶
MockExister_GetNamespace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNamespace'
func (*MockExister_GetNamespace_Call) Return ¶
func (_c *MockExister_GetNamespace_Call) Return(_a0 api.Namespace, _a1 bool) *MockExister_GetNamespace_Call
func (*MockExister_GetNamespace_Call) Run ¶
func (_c *MockExister_GetNamespace_Call) Run(run func(name string)) *MockExister_GetNamespace_Call
func (*MockExister_GetNamespace_Call) RunAndReturn ¶
func (_c *MockExister_GetNamespace_Call) RunAndReturn(run func(string) (api.Namespace, bool)) *MockExister_GetNamespace_Call
type StateChange ¶ added in v1.38.7
type StateChange struct {
// AppliedIndex is this apply's RAFT log index. A successful flip stores
// it as the namespace's new StateChangeIndex.
AppliedIndex uint64
// ExpectedIndex is the StateChangeIndex the flip requires the namespace
// to still be at. 0 skips the check.
ExpectedIndex uint64
}
StateChange carries the two RAFT indexes a state flip needs: one is written, the other is compared. Named fields rather than two uint64 parameters, which a caller could swap without the compiler noticing.