membershipindex

package
v0.2.21 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package membershipindex implements the UMI invariant reconciler: a controller that watches UserMembershipIndex CRs in root:railgrid:users and repairs rows that strand a user.

The invariant: every workspace-scope row implies an org-scope row for the same Organization. The portal's org switcher is built exclusively from org-scope rows (restapi.listOrgs), and every workspace lives inside an org — so a UMI holding a workspace-scope row with no matching org-scope row describes a workspace the user has been granted but can never reach. They see nothing, while every individual object (RBAC binding, UMI row, Membership CR) looks correct in isolation.

The REST layer keeps writing both rows on the happy path (restapi.addWorkspaceMembership cascades the org membership), but the index is maintained by dual writes across failure domains — a handler crash between writes, a partial rollout, or an older hub can all leave the index inconsistent. Following the model in platform-mesh's tenancy-operator (RFC 010), consistency of derived state is a controller's job, not a property every writer must individually guarantee: handlers record intent, this reconciler converges the index, and drift heals on the next resync instead of persisting until someone files a bug.

What it deliberately does NOT do:

  • Invent workspace rows from Membership CRs (the workspace-scope source of truth IS the UMI; there is nothing to reconcile against).
  • Resurrect rows for Organizations that no longer exist or are soft-deleted — teardown is the softdelete reconciler's domain, and healing must never race it back to life.
  • Touch roles on existing rows (the REST layer owns role changes).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewManager

func NewManager(cfg *rest.Config, scheme *runtime.Scheme) (manager.Manager, error)

NewManager constructs a controller-runtime manager bound to the root:railgrid:users workspace config (Bootstrapper.UsersConfig), matching the organization and softdelete managers. Separate manager so an invariant-repair crash can't take their workqueues down.

func SetupWithManager

func SetupWithManager(mgr manager.Manager, ensurer MembershipEnsurer) error

SetupWithManager registers the UserMembershipIndex watch with mgr.

Types

type MembershipEnsurer

type MembershipEnsurer interface {
	// EnsureOrgMembership creates an org-scope Membership CR inside the
	// Organization workspace granting userName the given role. Idempotent.
	EnsureOrgMembership(ctx context.Context, orgUUID, userName, role string) error
}

MembershipEnsurer is the one Bootstrapper capability this controller needs: recording the org-scope Membership CR that mirrors the healed index row. Narrow so tests fake it without an embedded kcp.

Implemented by *pkg/hub/kcp.Bootstrapper.

type Reconciler

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

Reconciler enforces the ws-row→org-row invariant on one UserMembershipIndex per reconcile.

func (*Reconciler) Reconcile

func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error)

Reconcile heals one user's index: for every org that appears only in workspace-scope rows, write the org-scope Membership CR + index row that make the org (and therefore those workspaces) reachable in the portal.

Jump to

Keyboard shortcuts

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