Documentation
¶
Index ¶
- Constants
- Variables
- func AccountRegion(ctx *AppContext) (string, string)
- func AccountRegionOrDefault(ctx *AppContext) (string, string)
- func CBORToJSON(data []byte) ([]byte, error)
- func HandleJSON[In, Out any](ctx context.Context, body []byte, fn func(context.Context, *In) (*Out, error)) (any, error)
- func HandleTarget(c *echo.Context, log *slog.Logger, serviceName, contentType string, ...) error
- func IsCBORRequest(r *http.Request) bool
- func JSONToCBOR(data []byte, binaryKeys map[string]bool) ([]byte, error)
- type AppContext
- type BackgroundWorker
- type ChaosProvider
- type CloudTrailEventInput
- type CloudTrailRecorder
- type DashboardProvider
- type DispatchFunc
- type Entry
- type ErrorHandlerFunc
- type FISActionDefinition
- type FISActionExecution
- type FISActionProvider
- type FISParamDef
- type JSONErrorResponse
- type JSONOpFunc
- type Matcher
- type Middleware
- type Provider
- type Purgeable
- type Registerable
- type Registry
- func (r *Registry) Count() int
- func (r *Registry) GetAll() []*Entry
- func (r *Registry) GetByName(name string) *Entry
- func (r *Registry) Register(svc Registerable, mws ...Middleware) error
- func (r *Registry) SetCloudTrailRecorder(rec CloudTrailRecorder)
- func (r *Registry) SetLatencyMs(ms int)
- func (r *Registry) Use(mw Middleware)
- type Resettable
- type ResourceObserver
- type Router
- type Service
- type Shutdowner
Constants ¶
const ( // PriorityHeaderExact is for services matched by an exact X-Amz-Target prefix. PriorityHeaderExact = 100 // PriorityHeaderPartial is for services matched by a partial header prefix (Lambda, KMS, SecretsManager). PriorityHeaderPartial = 95 // PriorityFormEncoded is for STS form-encoded POST requests. PriorityFormEncoded = 90 // PriorityPathVersioned is for services matched by a versioned path prefix (S3Control). PriorityPathVersioned = 85 // PriorityFormRDS is for RDS form-encoded query protocol (version 2014-10-31). PriorityFormRDS = 84 // PriorityFormDocDB is for DocDB form-encoded query protocol. Higher than RDS (84) to intercept DocDB requests first. PriorityFormDocDB = 85 // PriorityFormNeptune is for Neptune form-encoded query protocol. // Higher than RDS (84) to intercept Neptune requests first. PriorityFormNeptune = 85 // PriorityFormRedshift is for Redshift form-encoded query protocol (version 2012-12-01). PriorityFormRedshift = 83 // PriorityPathSubdomain is for OpenSearch and ElastiCache path-prefix matchers. PriorityPathSubdomain = 82 // PriorityFormStandard is for EC2, IAM, and SES standard form-encoded query protocol. PriorityFormStandard = 80 // PriorityTargetPrefixed is for Kinesis with its versioned X-Amz-Target prefix. PriorityTargetPrefixed = 75 // PriorityPathUI is for the Dashboard UI path-based routes. PriorityPathUI = 50 // PriorityCatchAll is for S3, which uses a low-priority Host-header catch-all. PriorityCatchAll = 0 )
Routing priority constants control the order in which service matchers are evaluated. Higher values are evaluated first. Services are grouped into tiers:
- 100 (HeaderExact): Services matched by an exact X-Amz-Target prefix. These are the most specific and should always win.
- 95 (HeaderPartial): Services matched by a looser header prefix check (e.g. Lambda by path + method, KMS/SecretsManager by target prefix).
- 90 (FormEncoded): STS – form-encoded POST to the root path.
- 85 (PathVersioned): Services matched by a versioned path prefix (S3Control).
- 85 (FormDocDB): DocDB – form-encoded, versioned query protocol (intercepted before RDS).
- 85 (FormNeptune): Neptune – form-encoded, versioned query protocol (intercepted before RDS).
- 84 (FormRDS): RDS – form-encoded, versioned query protocol.
- 83 (FormRedshift): Redshift – form-encoded, version 2012-12-01.
- 82 (PathSubdomain): OpenSearch / ElastiCache – path-prefix matchers that could overlap with form-encoded services.
- 80 (FormStandard): EC2, IAM, SES – standard form-encoded query protocol.
- 75 (TargetPrefixed): Kinesis – X-Amz-Target with a versioned prefix.
- 50 (PathUI): Dashboard – path-based UI routes.
- 0 (CatchAll): S3 – low-priority catch-all Host-header matcher.
const ContentTypeCBOR = "application/x-amz-cbor-1.1"
ContentTypeCBOR is the AWS CBOR wire protocol content type used by DynamoDB, Kinesis, and Timestream.
Variables ¶
var ErrServiceAlreadyRegistered = errors.New("service already registered")
ErrServiceAlreadyRegistered is returned when a service with the same name is already registered.
Functions ¶
func AccountRegion ¶
func AccountRegion(ctx *AppContext) (string, string)
AccountRegion returns the configured AWS account ID and region from the AppContext's Config when it implements config.Provider, or ("", "") otherwise.
It collapses the boilerplate every service provider repeats:
if cp, ok := ctx.Config.(config.Provider); ok {
cfg := cp.GetGlobalConfig()
accountID = cfg.GetAccountID()
region = cfg.GetRegion()
}
The empty fallback matches that hand-rolled behaviour exactly, so backends keep applying their own defaults when no config is wired.
func AccountRegionOrDefault ¶
func AccountRegionOrDefault(ctx *AppContext) (string, string)
AccountRegionOrDefault is like AccountRegion but falls back to config.DefaultAccountID and config.DefaultRegion when no config.Provider is present. It collapses the most common provider idiom:
accountID := config.DefaultAccountID
region := config.DefaultRegion
if cp, ok := ctx.Config.(config.Provider); ok {
cfg := cp.GetGlobalConfig()
accountID = cfg.GetAccountID()
region = cfg.GetRegion()
}
func CBORToJSON ¶
CBORToJSON decodes AWS CBOR-1.1 wire bytes to equivalent JSON bytes.
CBOR byte strings (major type 2) are base64-encoded in the JSON output, matching the JSON wire format that aws-sdk-go-v2 uses for binary attribute values.
func HandleJSON ¶
func HandleJSON[In, Out any]( ctx context.Context, body []byte, fn func(context.Context, *In) (*Out, error), ) (any, error)
HandleJSON is a generic dispatcher that decodes the JSON body into a typed input, calls fn, and returns the typed output as any. If body is non-empty and cannot be decoded, HandleJSON returns the decode error directly.
func HandleTarget ¶
func HandleTarget( c *echo.Context, log *slog.Logger, serviceName, contentType string, supportedOps []string, dispatch DispatchFunc, handleErr ErrorHandlerFunc, ) error
HandleTarget implements the X-Amz-Target JSON protocol dispatch pattern shared by many AWS JSON-protocol services (SSM, EventBridge, StepFunctions, CloudWatchLogs, etc.).
It performs:
- GET / → returns supportedOps as JSON
- Non-POST → 405 Method Not Allowed
- Missing or malformed X-Amz-Target → 400 Bad Request
- Body read failure → 500 Internal Server Error
- dispatch call → handleErr on error, else write response with contentType header
func IsCBORRequest ¶
IsCBORRequest returns true when the request carries an AWS CBOR-encoded body.
func JSONToCBOR ¶
JSONToCBOR encodes JSON bytes to AWS CBOR-1.1 wire bytes.
binaryKeys is an optional set of JSON object keys whose string values should be treated as standard base64-encoded binary data and encoded as CBOR byte strings (major type 2). Keys present in the set match any occurrence in the document regardless of nesting depth. A nil map means no binary fields.
For array values the parent key is inherited, so {"BS": ["abc","def"]} produces a CBOR list of byte strings when "BS" is in binaryKeys.
Types ¶
type AppContext ¶
type AppContext struct {
Config any
JanitorCtx context.Context
Logger *slog.Logger
PortAlloc *portalloc.Allocator
JanitorTimeout time.Duration
}
AppContext contains shared resources needed by services during initialization.
type BackgroundWorker ¶
BackgroundWorker is an optional interface that services can implement to start background tasks (e.g. async deletion janitors).
type ChaosProvider ¶
type ChaosProvider interface {
// ChaosServiceName returns the lowercase AWS-style service name used in
// fault rules (e.g. "s3", "dynamodb", "sqs").
ChaosServiceName() string
// ChaosOperations returns all operations that can be fault-injected.
// Implementations typically delegate to GetSupportedOperations().
ChaosOperations() []string
// ChaosRegions returns all regions this service instance handles.
// Typically returns the configured default region plus any regions
// that have active resources.
ChaosRegions() []string
}
ChaosProvider is an optional interface services implement to declare their chaos-injectable surface area. Services that implement this interface are automatically discovered by the Chaos API via the registry.
type CloudTrailEventInput ¶
type CloudTrailEventInput struct {
// EventName is the AWS API operation name, e.g. "CreateBucket", "RunInstances".
EventName string
// EventSource is the AWS service's CloudTrail event source, e.g. "s3.amazonaws.com".
EventSource string
// AwsRegion is the region the request targeted.
AwsRegion string
// Username identifies the caller. Empty when no signed identity was present.
Username string
// AccessKeyID is the SigV4 access key used to sign the request, if any.
AccessKeyID string
// ResourceName is the primary resource the operation acted on, if known.
ResourceName string
}
CloudTrailEventInput carries the fields the central service registry extracts from a single mutating API call so the CloudTrail backend can record a real management event. It is defined here (rather than reusing the cloudtrail package's own Event type) because services/cloudtrail already imports pkgs/service for its Provider/Registerable wiring, so the reverse import would create an import cycle.
type CloudTrailRecorder ¶
type CloudTrailRecorder interface {
// RecordManagementEvent records a single mutating API call as a CloudTrail
// management event so it is later returned by LookupEvents.
RecordManagementEvent(ev CloudTrailEventInput)
}
CloudTrailRecorder is implemented by the CloudTrail service backend to accept management events captured centrally by the service registry. The registry auto-discovers the live backend via SetCloudTrailRecorder; no service package other than cloudtrail need know about this interface.
type DashboardProvider ¶
type DashboardProvider interface {
// DashboardName returns the user-facing name for this service's dashboard tab.
// Example: "DynamoDB", "S3"
DashboardName() string
// DashboardRoutePrefix returns the URL path prefix for this service's dashboard routes.
// Example: "dynamodb", "s3"
DashboardRoutePrefix() string
// RegisterDashboardRoutes registers all dashboard routes for this service
// under the given Echo group. The group is mounted at /dashboard/{prefix}.
// The httpClient and endpoint are provided for services that need to make
// SDK calls back to the service (e.g., to list tables or buckets).
RegisterDashboardRoutes(
group *echo.Group,
httpClient any,
endpoint string,
)
}
DashboardProvider is an optional interface that services can implement to provide a dashboard UI. The dashboard automatically discovers and integrates services that implement this interface.
type DispatchFunc ¶
DispatchFunc is the signature for service-specific action dispatch functions. It receives the request context, the action name extracted from X-Amz-Target, and the raw request body; it returns pre-marshaled JSON or an error.
type Entry ¶
type Entry struct {
Registerable Registerable
Matcher Matcher
WrappedHandler echo.HandlerFunc
Priority int
}
Entry represents a registered service with its pre-wrapped handler and priority.
type ErrorHandlerFunc ¶
ErrorHandlerFunc is the signature for service-specific error handlers. It translates a dispatch error into an HTTP response.
type FISActionDefinition ¶
type FISActionDefinition struct {
ActionID string // e.g., "aws:ec2:stop-instances"
Description string
TargetType string // e.g., "aws:ec2:instance"; empty if action has no targets
TargetKey string // key name used in the Targets map (e.g., "Instances", "Roles"); defaults to "Targets"
Parameters []FISParamDef
}
FISActionDefinition describes a FIS action supported by a service.
type FISActionExecution ¶
type FISActionExecution struct {
ActionID string
Parameters map[string]string
Targets []string // resolved resource ARNs
Duration time.Duration // 0 means run indefinitely until stopped
}
FISActionExecution carries the runtime context for executing a single FIS action.
type FISActionProvider ¶
type FISActionProvider interface {
// FISActions returns the FIS action definitions this service supports.
FISActions() []FISActionDefinition
// ExecuteFISAction executes a FIS action against resolved targets.
// It is called by the FIS backend when an experiment's action begins.
// The implementation must be non-blocking or respect ctx cancellation.
ExecuteFISAction(ctx context.Context, action FISActionExecution) error
}
FISActionProvider is an optional interface services implement to declare FIS actions they support and to execute them. Services that implement this interface are automatically discovered by the FIS backend via the service registry, enabling zero-config action registration.
type FISParamDef ¶
FISParamDef describes a single parameter accepted by a FIS action.
type JSONErrorResponse ¶
JSONErrorResponse is the standard JSON error envelope for AWS JSON-protocol services. Used in X-Amz-Target dispatch to signal errors back to the SDK.
type JSONOpFunc ¶
JSONOpFunc is the function type for a dispatched JSON-protocol operation. Implementations are produced by WrapOp and collected in a dispatchTable map.
type Matcher ¶
Matcher determines whether an incoming request should be routed to a particular service handler. Matchers are evaluated by priority (higher priority = evaluated first).
type Middleware ¶
type Middleware func(echo.HandlerFunc) echo.HandlerFunc
Middleware defines a function that wraps an Echo handler.
type Provider ¶
type Provider interface {
// Name returns the name of the service provider.
Name() string
// Init initializes the service using the provided application context.
// It returns the Registerable service, or an error if initialization fails.
Init(ctx *AppContext) (Registerable, error)
}
Provider encapsulates the logic to initialize a service.
type Purgeable ¶
Purgeable is an optional interface for services that support automatically removing resources older than a specific cutoff time (used by AUTO_PURGE_TTL).
type Registerable ¶
type Registerable interface {
Service
ResourceObserver
// MatchPriority returns the priority for this service's matcher.
// Higher values are evaluated first. Examples:
// - Header-based matchers (DynamoDB): 100
// - Path-based matchers (Dashboard): 50
// - Catch-all matchers (S3): 0
MatchPriority() int
}
Registerable combines Service and ResourceObserver into a single interface for services that want to be registered with the service registry. This unified interface simplifies the registration contract.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry manages the ordered registration of services and applies observability wrapping and other middleware at registration time.
func (*Registry) Register ¶
func (r *Registry) Register(svc Registerable, mws ...Middleware) error
Register adds a service to the registry with optional per-service middleware. Returns error if service name already registered. Services are internally sorted by priority after registration.
func (*Registry) SetCloudTrailRecorder ¶
func (r *Registry) SetCloudTrailRecorder(rec CloudTrailRecorder)
SetCloudTrailRecorder configures the registry to capture a CloudTrail management event for every mutating request that reaches a registered service's handler. This is the single chokepoint through which every service's requests flow, so calling this once wires global CloudTrail capture without touching any individual service. Must be called before Register for services that should be captured (typically once, before the registration loop, since the recorder itself is usually one of the services being registered).
func (*Registry) SetLatencyMs ¶
SetLatencyMs configures per-request latency injection for all services registered after this call. A random sleep of [0, ms) milliseconds is inserted inside the telemetry wrapper so that operation duration metrics include the simulated latency. A value <= 0 disables latency injection.
func (*Registry) Use ¶
func (r *Registry) Use(mw Middleware)
Use adds a global middleware to the registry. Global middlewares are applied to all services registered AFTER the middleware is added.
type Resettable ¶
type Resettable interface {
Reset()
}
Resettable is an optional interface that services can implement to support clearing all in-memory state without restarting the process. Used by the POST /_gopherstack/reset endpoint for CI pipelines and rapid local development. Services that do not implement this interface are silently skipped during reset.
type ResourceObserver ¶
type ResourceObserver interface {
// ExtractOperation returns the operation name (e.g., "GetItem", "PutObject").
// Used in metrics labels.
ExtractOperation(c *echo.Context) string
// ExtractResource returns the resource identifier (e.g., table name, bucket name).
// Used in metrics labels.
ExtractResource(c *echo.Context) string
}
ResourceObserver extracts metrics labels from requests for a specific service. Used by the metrics wrapper to instrument operations.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router evaluates matchers by priority and routes requests to the first matching service. Implements centralized routing logic that replaces scattered pre-middleware and manual routing checks.
func NewServiceRouter ¶
NewServiceRouter creates a router from the registered services. Services are sorted by priority (highest first) for evaluation.
func (*Router) RouteHandler ¶
func (r *Router) RouteHandler() echo.MiddlewareFunc
RouteHandler returns an Echo middleware that evaluates all registered service matchers by priority and routes to the first matching service. If no service matches, it falls back to the next handler (standard Echo routing).
type Service ¶
type Service interface {
// Name returns the service identifier (e.g., "DynamoDB", "S3").
// Used in metrics labels and logging.
Name() string
// Handler returns the Echo handler function for this service.
Handler() echo.HandlerFunc
// RouteMatcher returns a function that determines if an incoming
// Echo request should be routed to this service. Matchers are
// evaluated in registration order. Return true to route here,
// false to continue to next service.
RouteMatcher() Matcher
// GetSupportedOperations returns a list of operations this service
// supports (e.g., ["GetItem", "PutItem", "Query"] for DynamoDB).
GetSupportedOperations() []string
}
Service represents an AWS-compatible service that can be registered with the service router. Each service provides an Echo handler, routing matcher, and observability information.
type Shutdowner ¶
Shutdowner is an optional interface that services can implement to perform cleanup of background goroutines and resources during graceful shutdown. It is called after the HTTP server has stopped accepting new requests. Services that do not implement this interface are silently skipped.