admin

package
v0.2.35 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package admin implements the platform-admin surface mounted at /api/admin/* and surfaced in the portal's gated /bonkers area. It lets a platform admin see all users / organizations / providers / root identities. It is read-only: provider provisioning (workspace + ServiceAccount + kubeconfig) is driven declaratively by the Provider CR reconciler (pkg/hub/providers/provider_controller.go), not by an admin HTTP action.

Index

Constants

This section is empty.

Variables

View Source
var ErrGracePeriodExpired = errors.New("soft-delete grace period has expired")

ErrGracePeriodExpired is returned by UndeleteOrgWorkspace when the workspace's soft-delete window has elapsed: the reconciler owns it now and a restore would race the cascade.

View Source
var ErrServerModeUnavailable = errors.New("requested kubeconfig server address is not configured on this hub")

ErrServerModeUnavailable is returned when a caller asks for a server mode this deployment has no URL for — chiefly ServerModeInternal on a hub started without --hub-internal-url.

Functions

func Middleware

func Middleware(resolver UserResolver, checker AdminChecker) func(http.Handler) http.Handler

Middleware gates a subrouter so only platform admins reach it: 401 when no identity resolves, 403 when the caller is authenticated but not an admin.

func UserFromContext added in v0.2.27

func UserFromContext(ctx context.Context) string

UserFromContext returns the admin identity Middleware stamped on the request, or "" outside a gated request. Handlers mounted behind the middleware use it to attribute their writes in logs.

Types

type AdminChecker

type AdminChecker interface {
	IsAdmin(ctx context.Context, userName string) bool
}

AdminChecker decides whether a resolved caller is a platform admin. The hub supplies an implementation that matches the User CR's name / email / rbacIdentity against the --admin-users allowlist.

type AdminCheckerFunc

type AdminCheckerFunc func(ctx context.Context, userName string) bool

AdminCheckerFunc adapts a function to AdminChecker.

func (AdminCheckerFunc) IsAdmin

func (f AdminCheckerFunc) IsAdmin(ctx context.Context, userName string) bool

IsAdmin implements AdminChecker.

type Handler

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

Handler serves the /api/admin/* endpoints.

func NewHandler

func NewHandler(svc *Service, userClient *railgridclient.Client, registry *providers.Registry) *Handler

NewHandler builds an admin Handler.

func (*Handler) GracePeriod added in v0.2.31

func (h *Handler) GracePeriod() time.Duration

GracePeriod returns the configured recovery window, falling back to softdelete.DefaultGracePeriod.

func (*Handler) Register

func (h *Handler) Register(r *mux.Router)

Register mounts the admin routes on r (already gated by the admin Middleware).

func (*Handler) WithPlanLookup added in v0.2.32

func (h *Handler) WithPlanLookup(exists func(ctx context.Context, name string) (bool, error)) *Handler

WithPlanLookup enables PUT /organizations/{name}/plan with the given existence check (metering.PlanExists in production).

func (*Handler) WithPlanReset added in v0.2.34

func (h *Handler) WithPlanReset(reset func(ctx context.Context, org string) error) *Handler

WithPlanReset makes PUT /organizations/{name}/plan with an empty plan also reset the organization's Entitlement to the default plan (metering.ResetPlan in production), so the route returns an organization to the default plan whoever put it on its current one.

func (*Handler) WithSoftDeleteGracePeriod added in v0.2.31

func (h *Handler) WithSoftDeleteGracePeriod(d time.Duration) *Handler

WithSoftDeleteGracePeriod sets the recovery window the undelete routes enforce and the listing reports. Wire it to the value the softdelete reconciler runs with; non-positive keeps softdelete.DefaultGracePeriod.

type KubeconfigServerMode

type KubeconfigServerMode string

KubeconfigServerMode selects which hub address is baked into a downloaded provider kubeconfig. The minted Secret carries exactly one server URL (the hub's --hub-internal-url when set, else --hub-external-url), but the same Secret feeds two different consumers: a provider installed by Helm into this cluster, which should stay on the in-cluster Service, and a provider run outside the cluster (another cluster, a laptop during development), which can only reach the public hostname. Whoever downloads the kubeconfig knows which one they are, so the choice is made per download rather than per deployment.

const (
	// ServerModeAsMinted leaves the server URL exactly as the Provider
	// controller wrote it. The default, so existing callers are unaffected.
	ServerModeAsMinted KubeconfigServerMode = ""
	// ServerModeExternal rewrites the server to the hub's external URL — for
	// providers running outside this cluster.
	ServerModeExternal KubeconfigServerMode = "external"
	// ServerModeInternal rewrites the server to the hub-internal URL (the
	// in-cluster Service) — for providers installed into this cluster. Keeps
	// provider→hub traffic off the public path.
	ServerModeInternal KubeconfigServerMode = "internal"
)

func ParseKubeconfigServerMode

func ParseKubeconfigServerMode(v string) (KubeconfigServerMode, error)

ParseKubeconfigServerMode maps the `server` query parameter to a mode. An empty value means "as minted". Unknown values are rejected rather than silently falling back, so a typo can't hand out the wrong address.

type OnboardedWorkspace

type OnboardedWorkspace struct {
	Name    string
	Cluster string
	Phase   string
}

OnboardedWorkspace mirrors providers.OnboardedWorkspace for the admin API.

type OrgWorkspace

type OrgWorkspace struct {
	UUID                string     `json:"uuid"`
	DisplayName         string     `json:"displayName"`
	ClusterName         string     `json:"clusterName"`
	Providers           []string   `json:"providers"`
	DeletionRequestedAt *time.Time `json:"deletionRequestedAt,omitempty"`
	// DeletionForced is set when the deletion was requested without the
	// recovery window: the cascade runs on the reconciler's next sweep and
	// a restore is refused.
	DeletionForced bool `json:"deletionForced,omitempty"`
}

OrgWorkspace is a child Workspace of an organization together with the provider names enabled in it (derived from the workspace's provider APIBindings).

type Service

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

Service performs read-only admin queries against kcp.

func NewService

func NewService(kcpConfig *rest.Config, hubExternalURL, hubInternalURL string, provOpts ...providers.ProvisionerOption) *Service

NewService returns an admin Service. hubExternalURL and hubInternalURL are the hub's --hub-external-url and --hub-internal-url; they let the kubeconfig download offer either address regardless of which one the Provider reconciler baked into the Secret. hubInternalURL may be empty, in which case only the external mode is offered.

func (*Service) AvailableKubeconfigServerModes

func (s *Service) AvailableKubeconfigServerModes() []KubeconfigServerMode

AvailableKubeconfigServerModes reports which modes this hub can actually serve, so the portal can offer only the ones that will work. External is present whenever --hub-external-url is set (always, in practice); internal only when --hub-internal-url is.

func (*Service) CreateProvider

func (s *Service) CreateProvider(ctx context.Context, name, displayName string) error

CreateProvider create-or-updates a Provider object in root:railgrid:system:providers. name drives the provisioned sub-workspace (root:railgrid:providers:<name>); displayName is informational. Idempotent.

func (*Service) DeleteProvider

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

DeleteProvider removes a Provider object from root:railgrid:system:providers. The reconciler's finalizer then tears down the sub-workspace. Idempotent.

func (*Service) GetProviderKubeconfig

func (s *Service) GetProviderKubeconfig(ctx context.Context, name string, mode KubeconfigServerMode) ([]byte, error)

GetProviderKubeconfig returns the minted kubeconfig the Provider controller wrote into a Secret in root:railgrid:system:providers. It reads the Provider's status.secretRef to locate the Secret (falling back to the "<name>-kubeconfig" / "default" / "kubeconfig" conventions). Returns a nil slice + nil error when the Provider exists but hasn't been provisioned yet (no Secret), so callers can surface "not ready".

mode re-points the server URL on the way out; the stored Secret is never modified. ServerModeAsMinted returns the bytes untouched.

func (*Service) ListOnboardedWorkspaces

func (s *Service) ListOnboardedWorkspaces(ctx context.Context) ([]OnboardedWorkspace, error)

ListOnboardedWorkspaces returns the provider sub-workspaces created by onboarding, so the admin UI can show providers that have been onboarded but whose Helm chart (and CatalogEntry) is not yet installed.

func (*Service) ListOrgWorkspaces

func (s *Service) ListOrgWorkspaces(ctx context.Context, orgUUID string) ([]OrgWorkspace, error)

ListOrgWorkspaces returns every child Workspace under the org at root:railgrid:tenants:{orgUUID}, enriched with display name, cluster name, soft-delete timestamp and the set of enabled provider names. Reads run with kcp-admin credentials, so the admin surface sees all workspaces regardless of per-user RBAC. Per-workspace lookups are best-effort: a workspace that hasn't reached Ready (no cluster) or whose provider listing fails still appears with whatever fields resolved.

func (*Service) RotateProviderCredential

func (s *Service) RotateProviderCredential(ctx context.Context, name string, mode KubeconfigServerMode) ([]byte, *providers.RotatedCredential, error)

RotateProviderCredential issues a NEW workspace credential for a platform provider's ServiceAccount, rewrites the kubeconfig Secret the Provider controller keeps in root:railgrid:system:providers, and returns the fresh kubeconfig in the same shape the download endpoint serves.

The Secret is rewritten rather than left alone because that Secret is where in-cluster consumers read the credential from: a rotation the Secret did not see would hand the operator a kubeconfig while every automated reader kept the retired one, and the retired one is on a deletion clock.

mode re-points the server URL on the way out, exactly as GetProviderKubeconfig does; the stored Secret always keeps the address the hub minted.

func (*Service) UndeleteOrgWorkspace added in v0.2.31

func (s *Service) UndeleteOrgWorkspace(ctx context.Context, orgUUID, wsUUID string, gracePeriod time.Duration) error

UndeleteOrgWorkspace clears the soft-delete annotation on the child Workspace at root:railgrid:tenants:{orgUUID}:{wsUUID} while it is still inside gracePeriod. Nil when the workspace was never soft-deleted (the caller's intent already holds); ErrGracePeriodExpired once the window has elapsed; kcp.ErrWorkspaceDeletionForced when the deletion was requested without a window, which is never restorable.

The bootstrapper's clear is a single conditional update that hands kcp conflicts back, so this mirrors the tenant REST handler: re-read after a conflict, retry only while the same deletion stamp is still present, and stop if a newer delete won the race and owns the recovery clock now.

type UserResolver

type UserResolver interface {
	ResolveUser(r *http.Request) (string, error)
}

UserResolver maps an inbound request to the caller's User CR name, or returns an error if no identity can be resolved. Mirrors tenant.UserResolver so the hub can reuse the same OIDC IdentifyUser plumbing.

type UserResolverFunc

type UserResolverFunc func(r *http.Request) (string, error)

UserResolverFunc adapts a function to UserResolver.

func (UserResolverFunc) ResolveUser

func (f UserResolverFunc) ResolveUser(r *http.Request) (string, error)

ResolveUser implements UserResolver.

Jump to

Keyboard shortcuts

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