Documentation
¶
Overview ¶
Package server provides a batteries-included gRPC server builder for Infoblox services. It assembles the framework interceptor chain (request-ID, error mapping, tenant-ID, fail-closed authz, field-mask validation, ETag preconditions, read-mask response shaping) and, optionally, an HTTP/JSON gateway in front of the gRPC endpoint.
Index ¶
- Constants
- func AssertAggregateBoundaries(methods []string, members []MemberBinding) error
- type Config
- type MemberBinding
- type ResilienceConfig
- type Server
- func (s *Server) AddReadinessCheck(checks ...sdkhealth.Check)
- func (s *Server) AddRules(rules ...authz.MethodRule)
- func (s *Server) GRPCAddr() string
- func (s *Server) GRPCServer() *grpc.Server
- func (s *Server) GatewayMux() *runtime.ServeMux
- func (s *Server) HTTPAddr() string
- func (s *Server) LROStore() lro.Store
- func (s *Server) MemberBindings() []MemberBinding
- func (s *Server) RecordMemberBinding(b MemberBinding)
- func (s *Server) RecordMethods(methods ...string)
- func (s *Server) RegisterGateway(fn func(context.Context, *runtime.ServeMux, *grpc.ClientConn) error)
- func (s *Server) Rules() []authz.MethodRule
- func (s *Server) Serve(ctx context.Context) error
Constants ¶
const DefaultGRPCAddr = ":9090"
DefaultGRPCAddr is the default listen address for the gRPC endpoint.
Variables ¶
This section is empty.
Functions ¶
func AssertAggregateBoundaries ¶ added in v0.19.0
func AssertAggregateBoundaries(methods []string, members []MemberBinding) error
AssertAggregateBoundaries returns an error if any aggregate MEMBER resource registers a write-capable standard method on the transport surface. methods is the full set of registered gRPC FullMethods (as recorded by RecordMethods); members is the accumulated set of member→root bindings. It is a pure function over (methods, members) so it can be unit-tested directly, and it is run at Serve beside the authz completeness gate (fail-closed, default-deny: a member resource cannot independently mutate — writes route through the root).
Reads (Get/List) are intentionally NOT considered: addressability is not write authority, and a read-only projection of a member is not a member write. Only the WriteMethods recorded on each binding are checked.
Types ¶
type Config ¶
type Config struct {
// GRPCAddr is the TCP address to listen on (e.g. ":9090" or ":0"). Required.
GRPCAddr string
// HTTPAddr is the optional gateway address (e.g. ":8080"). Empty disables
// the HTTP gateway.
HTTPAddr string
// Rules are the declared authz rules; they feed both grpcauthz (enforcement)
// and the field-mask interceptor (verb lookup).
Rules []authz.MethodRule
// Authorizer is the pluggable decision point. Defaults to
// authz.NewDevAuthorizer(nil) if nil.
Authorizer authz.Authorizer
// PrincipalFunc derives the authenticated authz.Principal from each request's
// context. When nil the principal is empty, so — with a default-deny
// Authorizer — every non-public method is denied (fail closed). For local
// development set grpcauthz.DevPrincipalFunc() to derive the principal from
// request metadata; in production supply one backed by a verified token.
PrincipalFunc grpcauthz.PrincipalFunc
// FeatureSource, when set, makes the gate entitlement-aware (P12): server.New
// wraps Authorizer with authz.WithEntitlement so the SAME decision enforces
// both a method's permission AND its declared entitlement Features
// (MethodRule.Features). Dev default is authz.StaticFeatures; production binds
// the licensing/entitlement service (the OPA sidecar already returns the
// combined decision, so it is wired here as the Authorizer and NOT wrapped).
// Nil = permission-only authz (unchanged).
FeatureSource authz.FeatureSource
// AlertSink receives alerts when a method declared authz.ModeAlert fails its
// policy decision but is allowed through (P12 observation mode). Defaults to a
// structured-log sink on Logger.
AlertSink authz.AlertSink
// UsageMeter, when set, enforces declared per-method quotas (MethodRule.Quota,
// P13) with a reserve→commit/release lifecycle around the handler — separate
// from the authz decision, running just after authz so the principal/tenant is
// established. Dev default is quota.NewMemoryMeter; production binds the
// token-allocation/usage service. Nil = no quota enforcement.
UsageMeter quota.Meter
// Interceptors are additional unary interceptors appended after the
// framework chain. They run post-handler too (an interceptor may observe or
// wrap the response), so a gRPC-side cross-cutting extension (e.g. an audit
// hook) wires in here — the way an Authorizer wires into Authorizer.
Interceptors []grpc.UnaryServerInterceptor
// HTTPMiddleware are net/http middlewares wrapping the REST gateway mux (the
// P2 HTTP extension seam). They wrap only the gateway routes — never the
// /healthz and /readyz probes — and run inside the SDK's tracing span;
// HTTPMiddleware[0] is the outermost wrapper. A REST request still traverses
// the full gRPC interceptor chain on the in-process hop, so these compose
// with (do not bypass) the gRPC stages. Used by an internal extension exactly
// as Interceptors is — e.g. an audit/identity HTTP middleware shipped in
// devedge-sdk-internal.
HTTPMiddleware []func(http.Handler) http.Handler
// DeduplicationStore is the idempotency store for DeduplicateUnary. Defaults to MemoryDeduplicationStore (10-minute TTL) when nil.
DeduplicationStore middleware.DeduplicationStore
// LROStore is the operation store for long-running operations (AIP-151).
// Defaults to lro.NewMemoryStore(1h) when nil.
LROStore lro.Store
// Logger is the structured logger the default chain's middleware.LoggingUnary
// writes one record per RPC to (trace-correlated, secret-redacted payloads at
// Debug). Defaults to slog.Default() when nil.
Logger *slog.Logger
// ReadinessChecks is the list of readiness checks the server runs on every
// /readyz probe and whenever it drives the gRPC health status. An empty slice
// means "always ready" (the default). Each check is bounded by a 2s timeout;
// a single failure flips /readyz to 503 and the gRPC overall status to
// NOT_SERVING. Liveness (/healthz, gRPC health Check on "") is always
// process-up only — deps never go in the liveness check.
ReadinessChecks []sdkhealth.Check
// Resilience configures optional resilience policy interceptors inserted into
// the default chain. server.New applies a 30-second request timeout when the
// zero value is supplied; rate limiting and circuit breaking are opt-in (nil).
Resilience ResilienceConfig
}
Config carries the options for constructing a Server.
type MemberBinding ¶ added in v0.19.0
type MemberBinding struct {
// Resource is the member resource's Go type name (e.g. "Item").
Resource string
// Root is the owning aggregate root's message name (e.g. "Order").
Root string
// WriteMethods are the gRPC FullMethod names of the write-capable standard
// methods this member service registers (e.g.
// "/order.v1.ItemService/CreateItem"). A non-empty intersection with the
// registered method set is the boundary violation the gate fails on.
WriteMethods []string
}
MemberBinding records that a service's resource is a DDD aggregate MEMBER owned by Root, together with the write-capable standard methods (Create/Update/ Delete/Undelete/Batch*) the service registers on the transport surface. The generated Register<Svc> contributes one MemberBinding per member service (via Server.RecordMemberBinding); the boot-time boundary gate AssertAggregateBoundaries reads the accumulated set at Serve.
A member resource is addressable for READS (Get/List) but written THROUGH its root, so a registered member write is a boundary violation that fails closed — mirroring the authz completeness gate (an undeclared method is denied).
type ResilienceConfig ¶ added in v0.25.0
type ResilienceConfig struct {
// RequestTimeout bounds every unary handler invocation. server.New defaults
// to 30s when this field is zero; set to resilience.NoTimeout to explicitly
// disable the timeout. Per-method overrides (PerMethodTimeout) take
// precedence; a per-method value of resilience.NoTimeout disables that
// method's timeout regardless of RequestTimeout.
//
// A handler that exceeds the deadline receives codes.DeadlineExceeded.
// Handlers should honour ctx.Done() for clean early exit.
RequestTimeout time.Duration
// PerMethodTimeout overrides RequestTimeout for specific gRPC full-method
// names (e.g. "/mypackage.MyService/LongOp": 5*time.Minute). Set a method's
// value to resilience.NoTimeout to disable the timeout for that method only.
PerMethodTimeout map[string]time.Duration
// RateLimiter, when non-nil, is inserted right after TenantIDUnary (before
// authz) to shed excess load early with codes.ResourceExhausted. Default
// nil = off. Use resilience.NewTokenBucket or supply your own implementation.
RateLimiter resilience.RateLimiter
// CircuitBreaker, when non-nil, wraps handler invocations just inside the
// framework chain. Default nil = off. Plug in sony/gobreaker,
// afex/hystrix-go, or any resilience.CircuitBreaker implementation.
CircuitBreaker resilience.CircuitBreaker
}
ResilienceConfig holds the resilience policy settings for the server's default interceptor chain.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the assembled gRPC server (plus optional HTTP gateway).
func New ¶
New validates cfg and constructs a Server. It builds the framework interceptor chain and wires the authz rules into both the authorizer and the field-mask validator. Returns an error if any required field is missing.
func (*Server) AddReadinessCheck ¶ added in v0.28.0
AddReadinessCheck appends a readiness check to the server's accumulated set (Config.ReadinessChecks seeds it). The /readyz endpoint and the gRPC health loop read the live set on every probe, so a check contributed after New — e.g. by a servicekit module's HealthRegistry during composed-host registration — is aggregated like any configured check. Call before Serve.
func (*Server) AddRules ¶ added in v0.18.0
func (s *Server) AddRules(rules ...authz.MethodRule)
AddRules appends authz rules to the server's accumulated set. The generated Register<Svc>/Register<Svc>WithRepository call it with the service's <Svc>AuthzRules so the developer never hand-assembles Config.Rules. The authz and field-mask interceptors read the live set, and the boot-time completeness gate runs over it at Serve. Call before Serve.
func (*Server) GRPCAddr ¶
GRPCAddr returns the actual bound gRPC address once Serve has started (useful when GRPCAddr was ":0"); before that it returns the configured address.
func (*Server) GRPCServer ¶
GRPCServer returns the underlying *grpc.Server so callers can register their service implementations on it.
func (*Server) GatewayMux ¶
GatewayMux returns the HTTP gateway mux, or nil when no HTTP gateway is configured.
func (*Server) HTTPAddr ¶
HTTPAddr returns the actual bound HTTP gateway address once Serve has started (useful when HTTPAddr was ":0"); before that it returns the configured address. Returns "" when no HTTP gateway is configured.
func (*Server) LROStore ¶
LROStore returns the long-running operation store this server was configured with.
func (*Server) MemberBindings ¶ added in v0.19.0
func (s *Server) MemberBindings() []MemberBinding
MemberBindings returns the accumulated DDD aggregate member→root bindings.
func (*Server) RecordMemberBinding ¶ added in v0.19.0
func (s *Server) RecordMemberBinding(b MemberBinding)
RecordMemberBinding records that a service's resource is a DDD aggregate MEMBER owned by a root (with the write methods it registers). The generated Register<Svc> of a member service calls it; the boundary gate AssertAggregateBoundaries runs over the accumulated set at Serve (fail-closed: a member that registers a write method does not serve). Call before Serve.
func (*Server) RecordMethods ¶ added in v0.18.0
RecordMethods records gRPC FullMethods registered with the server so the completeness gate at Serve can verify each has a rule or a public exemption. The generated Register<Svc> calls it with the service's method names.
func (*Server) RegisterGateway ¶
func (s *Server) RegisterGateway(fn func(context.Context, *runtime.ServeMux, *grpc.ClientConn) error)
RegisterGateway records a gateway registration function to be invoked against the gateway mux and the in-process gRPC connection when Serve starts. It is a no-op at runtime unless an HTTP gateway is configured.
func (*Server) Rules ¶
func (s *Server) Rules() []authz.MethodRule
Rules returns the accumulated authz rule set: Config.Rules plus everything contributed via AddRules (e.g. by the generated Register<Svc>).