Documentation
¶
Overview ¶
Package lambdaapp runs sluis as AWS Lambda functions: one binary, one zip, three functions, the role chosen by SLUIS_ROLE (docs/integrations/aws-lambda.md).
http the issuer and the console behind an API Gateway HTTP API github the GitHub roster controller: one pass of one organisation per invocation slack the Slack roster controller: one pass of one workspace per invocation
This package assembles each role from the same pieces the Kubernetes process is assembled from (internal/rosterapp and the controllers' apps), and adds the two things Lambda needs: translating the platform's events, and reading secrets from SSM at cold start. It names no cluster, NATS or Valkey client, and cmd/sluis-lambda's import guard keeps it so.
Index ¶
- Constants
- func ParseEvent(payload json.RawMessage) (invoke.Event, error)
- func Request(ctx context.Context, event events.APIGatewayV2HTTPRequest) (*http.Request, error)
- func Response(status int, header http.Header, body []byte) events.APIGatewayV2HTTPResponse
- type Controller
- type ExportsResult
- type Function
- type HTTP
- func (h *HTTP) Handle(ctx context.Context, payload json.RawMessage) (any, error)
- func (h *HTTP) Serve(ctx context.Context, event events.APIGatewayV2HTTPRequest) (resp events.APIGatewayV2HTTPResponse)
- func (h *HTTP) WithExports(run func(context.Context) (ExportsResult, error)) *HTTP
- func (h *HTTP) WithRefresh(run func(context.Context) (RefreshResult, error)) *HTTP
- type Handler
- type Pass
- type RefreshResult
- type Result
Constants ¶
const ( // KindTick is what an EventBridge Scheduler schedule sends, one per target. KindTick = "tick" // KindRun is what the http function sends when somebody asks for a pass now // (internal/port/invoke). KindRun = invoke.KindRun )
The event kinds of a controller function. Both run the same pass; they differ in who asked.
const ( // OutcomeRan is a pass that ran to its end. OutcomeRan = "ran" // OutcomeUnknown is a run-now of a target this controller does not run: the // notification was sent to every controller because nobody knew which kind // the target is, and the other one ends here, cleanly. OutcomeUnknown = "unknown" // OutcomeContended is a target another invocation holds the lease of: the // pass is its, and this one ends cleanly. It is not a failure, so the // platform neither retries it nor counts it as an error. OutcomeContended = "contended" )
The outcomes of a controller invocation.
const ( RoleHTTP = "http" RoleGitHub = "github" RoleSlack = "slack" )
The roles, the values of SLUIS_ROLE.
const (
// EnvRole is the function's role: http, github or slack. Required.
EnvRole = "SLUIS_ROLE"
)
The environment of a function. Everything else is the configuration documents', OpenTelemetry's own OTEL_* variables, or the platform's: SLUIS_CONFIG (config.EnvConfig) names the service document, in the configuration layer mounted at /opt/sluis, and the secrets it names are read from SSM by the `secrets` source it declares.
const KindExports = "exports"
KindExports is the event an EventBridge Scheduler schedule sends the `http` function to keep the exports (the copies of secrets under /sluis/export/...) current: {"kind":"exports"}. There is no loop to do it on Lambda.
const KindRefresh = "refresh"
KindRefresh is the event an EventBridge Scheduler schedule sends the `http` function to take a new snapshot of every connected workspace's directory: {"kind":"refresh"}. The Kubernetes server does it on a ticker; there is no loop on Lambda, and a snapshot that is not refreshed stops being authoritative after the freshness window, which sign-in refuses on.
Variables ¶
This section is empty.
Functions ¶
func ParseEvent ¶
func ParseEvent(payload json.RawMessage) (invoke.Event, error)
ParseEvent reads and checks a controller function's event.
func Request ¶
Request makes the http.Request an event describes. The headers arrive lower-cased and the cookies apart from them, and the body is base64 when the gateway says so.
Types ¶
type Controller ¶
type Controller struct {
// Name is the controller's, in log lines.
Name string
// Open assembles the controller.
Open func(ctx context.Context) (Pass, error)
Log *slog.Logger
// Unknown says an error is the controller not running that target.
Unknown func(error) bool
}
Controller runs one pass of one target per invocation.
The controller is assembled per invocation and closed at its end, as `sluis tick` does: the audit emitter delivers asynchronously, and a function that is frozen between invocations would hold its queue for hours. What is per process stays per process: the configuration, read and validated at cold start, and the secrets resolved into the environment.
func (*Controller) Handle ¶
func (c *Controller) Handle(ctx context.Context, payload json.RawMessage) (any, error)
Handle implements Handler: payload is {"kind":"tick"|"run","target":"<id>"}.
type ExportsResult ¶ added in v1.59.0
type ExportsResult struct {
Kind string `json:"kind"`
// Outcome is "ran", "none" (no export is declared) or "failed".
Outcome string `json:"outcome"`
Exports int `json:"exports"`
Done int `json:"done"`
Contended int `json:"contended"`
Failed int `json:"failed"`
}
ExportsResult is what an exports invocation returns.
type Function ¶
type Function struct {
Role string
Handler Handler
// Flush sends what telemetry holds; the platform freezes the process when
// an invocation returns, and a batch waiting for its timer waits for the
// next invocation.
Flush func(context.Context)
// Close releases what the role holds, at shutdown.
Close func()
}
Function is a role, assembled at cold start and ready to be invoked.
type HTTP ¶
type HTTP struct {
// contains filtered or unexported fields
}
HTTP serves API Gateway HTTP API events (payload format 2.0) with an http.Handler: the same mux the Kubernetes server serves on its listener.
func (*HTTP) Serve ¶
func (h *HTTP) Serve(ctx context.Context, event events.APIGatewayV2HTTPRequest) (resp events.APIGatewayV2HTTPResponse)
Serve runs one request through the handler and returns its response. A request that cannot be made into an http.Request is a 400, and a handler that panics a 500: neither is an error of the invocation, which the platform would retry.
func (*HTTP) WithExports ¶ added in v1.59.0
WithExports makes the function answer {"kind":"exports"} events with run.
func (*HTTP) WithRefresh ¶ added in v1.61.1
WithRefresh makes the function answer {"kind":"refresh"} events with run.
type Pass ¶
type Pass interface {
// Pass runs the target's pass under its lease; false, with no error, means
// another runner holds it.
Pass(ctx context.Context, target string, unsafeLocal bool) (ran bool, err error)
// Close flushes what the pass recorded.
Close() error
}
Pass is one assembled controller, for one invocation.