lambdaapp

package
v1.74.0-rc.2 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package lambdaapp runs sluis as ONE AWS Lambda function: one binary, one zip, one function (docs/reference/lambda.md). The function takes

  • API Gateway HTTP API events: the issuer and the console, the same mux the Kubernetes process serves on its listener;
  • {"kind":"tick"|"run","target":"<id>"}: one pass of one target under its lease, by the controller the policy says the target belongs to (the GitHub controller's organisations and `github:links`, the Slack controller's workspaces). `tick` is what an EventBridge Scheduler schedule sends, `run` what a console request sends (internal/port/invoke);
  • {"kind":"cloudflare"}: the rotation of the Cloudflare credentials that are due (the `cloudflare` section), which has no loop to run in on Lambda;
  • {"kind":"refresh"}: the directory refresh, which has no loop to run in on Lambda.

This package assembles the function 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. The controllers named in the service document (`controllers`) do not run their loops here: each is assembled per invocation that needs it. It names no cluster, NATS or Valkey client, and cmd/sluis-lambda's import guard keeps it so.

Index

Constants

View Source
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.

View Source
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.

View Source
const KindCloudflare = "cloudflare"

KindCloudflare is the event an EventBridge Scheduler schedule sends the `http` function to rotate the Cloudflare credentials that are due: {"kind":"cloudflare"}. A minute's schedule costs one read of the secrets store per preset until a rotation is due.

View Source
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.

func Response

func Response(status int, header http.Header, body []byte) events.APIGatewayV2HTTPResponse

Response makes an event's response of what a handler wrote. Set-Cookie goes in the response's cookies, as the gateway requires (a header of that name is dropped), the other headers keep their values comma-joined, and the body is base64 when it is not text.

Types

type CloudflareResult added in v1.74.0

type CloudflareResult struct {
	Kind    string `json:"kind"`
	Presets string `json:"presets"`
	Failed  int    `json:"failed"`
}

CloudflareResult is what a cloudflare invocation returns.

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 Function

type Function struct {
	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 function holds, at shutdown.
	Close func()
}

Function is the function, assembled at cold start and ready to be invoked.

func Open

func Open(ctx context.Context, getenv func(string) string) (*Function, error)

Open assembles the function. getenv is the process's.

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 NewHTTP

func NewHTTP(handler http.Handler, settle func(), log *slog.Logger) *HTTP

NewHTTP adapts handler. settle may be nil.

func (*HTTP) Handle

func (h *HTTP) Handle(ctx context.Context, payload json.RawMessage) (any, error)

Handle implements Handler: payload is an API Gateway HTTP API event.

func (*HTTP) Serve

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) WithCloudflare added in v1.74.0

func (h *HTTP) WithCloudflare(run func(context.Context) (failed int, summary string, err error)) *HTTP

WithCloudflare makes the function answer {"kind":"cloudflare"} events with run.

func (*HTTP) WithControllers added in v1.63.0

func (h *HTTP) WithControllers(kindOf func(target string) string, controllers map[string]*Controller) *HTTP

WithControllers makes the function answer {"kind":"tick"|"run","target":...} events by running one pass of the target under the controller of its kind (the controllers' names are the keys: "github", "slack"). kindOf says which kind a target is, from the policy that declares it; an empty answer is a target nobody declares.

func (*HTTP) WithRefresh added in v1.61.1

func (h *HTTP) WithRefresh(run func(context.Context) (RefreshResult, error)) *HTTP

WithRefresh makes the function answer {"kind":"refresh"} events with run.

type Handler

type Handler interface {
	Handle(ctx context.Context, payload json.RawMessage) (any, error)
}

Handler is one function's entry point: the platform's event in, a result out.

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.

type RefreshResult added in v1.61.1

type RefreshResult struct {
	Kind       string `json:"kind"`
	Workspaces int    `json:"workspaces"`
	Ran        int    `json:"ran"`
	Contended  int    `json:"contended"`
	Failed     int    `json:"failed"`
}

RefreshResult is what a refresh invocation returns.

type Result

type Result struct {
	Kind    string `json:"kind"`
	Target  string `json:"target"`
	Outcome string `json:"outcome"`
}

Result is what a controller invocation returns.

Jump to

Keyboard shortcuts

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