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
- func AssertReferenceTargets(batchTargets map[string]struct{}, references []reference.Reference) error
- type Config
- type HTTPHandler
- 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) RecordBatchTarget(resourceType string)
- func (s *Server) RecordExternalReferenceTarget(resourceType string)
- func (s *Server) RecordMemberBinding(b MemberBinding)
- func (s *Server) RecordMethods(methods ...string)
- func (s *Server) RecordReferences(refs ...reference.Reference)
- func (s *Server) References() []reference.Reference
- 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.
func AssertReferenceTargets ¶ added in v0.45.0
func AssertReferenceTargets(batchTargets map[string]struct{}, references []reference.Reference) error
AssertReferenceTargets returns an error if any declared cross-service reference names a target resource type that is NOT batch-fetchable — i.e. no service on this server registered a generated AIP-137 BatchGet for that type (F041 G-3).
batchTargets is the set of resource types that serve BatchGet (recorded by the generated Register<Svc> via Server.RecordBatchTarget); references is the accumulated set of cross-service references (via Server.RecordReferences). It is a pure function over (batchTargets, references) so it is unit-testable, and it runs at Serve beside the authz completeness and aggregate boundary gates.
This is the registration-time BACKSTOP of the fail-loud rule: the primary gate is at codegen (protoc-gen-svc makes a reference target's repository a persistence.BatchRepository, so a non-batch repo fails to compile). This gate additionally catches cross-repo / version skew that local codegen cannot see — a reference to a target served by a DIFFERENT service/binary that does not expose BatchGet. Fail-closed: an unresolvable reference must not serve, never a silent runtime N+1.
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.
//
// When Authenticator is set and PrincipalFunc is nil, PrincipalFunc defaults
// to authn.VerifiedPrincipal so the authorizer reads the token-verified
// principal the authentication interceptor stashed (the trusted path).
PrincipalFunc grpcauthz.PrincipalFunc
// Authenticator, when set, inserts the WS-026 authentication interceptor
// BEFORE the authz interceptor: it verifies the bearer from request metadata
// (signature + iss/aud/exp against the configured issuer/JWKS) and stashes the
// resulting authz.Principal via middleware.WithPrincipal, which the authorizer
// then reads through authn.VerifiedPrincipal. An invalid bearer is rejected
// with codes.Unauthenticated (fail closed); a request with no bearer passes to
// the authorizer with an empty principal (public methods still work).
//
// Nil preserves today's behavior (no verification stage; the principal comes
// from PrincipalFunc alone). The concrete verifier is authn/oidc.Authenticator
// (JOSE/JWKS), kept in a nested module so the SDK root stays dependency-light.
Authenticator authn.Authenticator
// 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
// HTTPHandlers mount custom net/http handlers on the HTTP server at path
// patterns, for endpoints that are NOT REST-gateway routes — an OIDC
// provider's authorization/token/JWKS/discovery endpoints, webhooks, a login
// UI, or static assets. Each handler is mounted on the outer mux by its
// net/http ServeMux Pattern, so a more specific pattern (e.g. "/oauth/") wins
// over the gateway catch-all ("/"); the /healthz and /readyz probes always take
// precedence and cannot be shadowed. A handler MAY claim the "/" pattern to
// replace the gateway catch-all entirely (e.g. an OP library that serves all
// its own subpaths). Handlers run inside the SDK's HTTP tracing span but do NOT
// traverse the gRPC interceptor chain — they are not gateway routes, so
// authentication/authorization for them is the handler's own responsibility.
// Requires HTTPAddr to be set.
HTTPHandlers []HTTPHandler
// DeduplicationStore is the idempotency store for DeduplicateUnary. Defaults to MemoryDeduplicationStore (10-minute TTL) when nil.
DeduplicationStore middleware.DeduplicationStore
// DurableDedup, when set, selects the durable, exactly-once idempotency path
// (middleware.DurableDeduplicateUnary) over the best-effort in-memory
// DeduplicationStore: the idempotency record is claimed and completed inside
// the handler's transaction, so a committed effect always has a retrievable
// response and a retry after a crash/restart or on another pod replays the
// ORIGINAL response verbatim. Requires both Store and Tx. When nil the
// server keeps the in-memory path (the zero-config default). See WS-043 /
// spec 048.
DurableDedup *middleware.DurableDedup
// 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 HTTPHandler ¶ added in v0.53.0
type HTTPHandler struct {
// Pattern is a net/http ServeMux pattern (e.g. "/oauth/", "/keys",
// "/.well-known/openid-configuration", or "/" to replace the gateway
// catch-all). Must be non-empty and must not be a reserved probe path.
Pattern string
// Handler serves requests matching Pattern. Must be non-nil.
Handler http.Handler
}
HTTPHandler mounts a custom net/http handler on the server's HTTP endpoint at a path pattern, alongside the REST gateway. It is the seam for serving HTTP endpoints that are not gRPC-gateway routes (see Config.HTTPHandlers).
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) RecordBatchTarget ¶ added in v0.45.0
RecordBatchTarget declares that resourceType is served by a generated AIP-137 BatchGet on this server — i.e. it is a batch-fetchable reference target. The generated Register<Svc> of a service exposing BatchGet<R> calls it; the reference gate at Serve matches each recorded reference's TargetType against this set. Call before Serve.
func (*Server) RecordExternalReferenceTarget ¶ added in v0.49.0
RecordExternalReferenceTarget declares that resourceType is a reference target served by ANOTHER process — the split-microservice federation case, where this service references a resource whose owning service (and its BatchGet<Target>) runs in a different binary. The reference gate then treats the target as resolvable elsewhere and does not require a local BatchGet, and the composition layer (for example a federationgql gateway) does the actual batch fetch. Call it after Register<Svc>WithRepository and before Serve, once per external target.
Unlike Server.RecordBatchTarget, this does NOT advertise a local BatchGet for the type; it only tells the gate the target is batch-fetchable in another process. Use RecordBatchTarget when THIS server serves BatchGet<Target>.
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) RecordReferences ¶ added in v0.45.0
RecordReferences records cross-service resource references declared by a service (F041). The generated Register<Svc> of a service with a google.api.resource_reference field calls it; the reference gate AssertReferenceTargets runs over the accumulated set at Serve (fail-closed: a reference whose target type serves no BatchGet does not serve). Call before Serve.
func (*Server) References ¶ added in v0.45.0
References returns the accumulated cross-service references (F041).
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>).