Help us shape the future of Go! Take the 2026 Go Developer Survey

generic

package
v0.2.0 Latest Latest
Warning

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

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

Documentation

Overview

Package generic emulates AWS services from their botocore models.

A service here is a model file plus, where it matters, a few overrides. The engine reads the model's shapes and HTTP bindings and speaks the json 1.0/1.1, query, ec2, rest-json, rest-xml and Smithy RPCv2 CBOR protocols (document shapes pass through as free-form JSON). It infers resources from operation names and stores them, so create, describe, list, update, delete and tagging work without any per-service code.

Adding a service

  1. Add the botocore directory name (the one under botocore/data) to services.txt.
  2. Run `go generate ./internal/aws/generic`. It fetches the pinned botocore wheel (scripts/models.sh), writes models/<name>.json.gz and refreshes models/index.json.
  3. That is all: Services() returns a factory for every embedded model and pogi.go registers each one that has no hand-written service of the same name. The service is named after the botocore directory.
  4. Add a test with the official SDK client (see codeartifact_test.go). If something comes back wrong, fix it in the engine when other services would benefit, else with an override.

A service's name, signing name and target prefix come from the model, so routing needs nothing more. When a hand-written service already owns the signing name, a Query service is routed by its Version parameter instead (Classic ELB beside ELB v2), and a REST service by whether the request is one of its operations and is signed for it (the Bedrock services all sign as "bedrock").

What the engine infers

  • Create<X>, Put<X> and Register<X> create a resource of type X (a prefix such as In, For or From ends the name: PutQuotaIntoTemplate is a Quota). Describe<X>/Get<X> read one, List<X>s and Describe<X>s list them, Update<X>/Modify<X> change one, Delete<X>/Deregister<X> remove one. TagResource, UntagResource, ListTagsForResource, AddTags and RemoveTags work on any resource by ARN or identifier; Tags and AddTags/RemoveTags members of create and update calls are kept as tags.
  • A type's identifiers are the required string members of its Get, Describe or Delete call (parents included: a filter is keyed by its detector and its name). The member named after the type (<X>Name, <X>Id, <X>Arn, Name, Id, Arn) is the one the service makes up when a create call leaves it out, from the member's pattern or as <prefix>-<hex>.
  • A resource keeps the merged input of its create and update calls. Outputs are filled by member name from it, from the request, and from the identifiers, ARN, tags, timestamps and the account. A status or state member with an enum gets a ready value (ACTIVE, AVAILABLE and so on); required numbers, booleans and lists get zero values so that clients never read a missing member.
  • Lists page with the model's paginators (or by member names), filter by identifiers and by members that match stored members, and a Describe with identifiers that match nothing is a not-found error.
  • Errors use the model's shapes: the declared not-found, already-exists and validation errors, else ResourceNotFoundException, ConflictException and ValidationException.

Overrides and hooks

Override replaces one operation; Hook runs after one succeeds. Both are registered by service and operation name, usually from an init function in <service>.go in this package (see elb.go):

generic.Override("efs", "DescribeLifecycleConfiguration", func(c *generic.Call) (map[string]any, error) {
	out, err := c.Default() // the engine's own result
	...
	return out, nil // keyed by the model's member names
})
generic.Hook("guardduty", "CreateDetector", func(c *generic.Call) { /* c.Res is the new detector */ })

An override that must write a whole operation's response itself (an event stream) sets Call.Stream; see ai.go. Raw lets a service answer requests that are not operations of its model (the Prometheus API of Managed Prometheus), and OnClose runs a function when the hub shuts the service down (a listener, a store). A service with work of its own (budget alerts, report delivery) starts it from a function added to starters, with Service.Every; Service.Tick runs that work once, for tests, and Service.Close stops it.

A Call carries the parsed input (c.In, keyed by member names, as map[string]any), the account and region, and the hub. c.Get, c.List and c.Put read and write resources; c.NotFound, c.Exists and c.Invalid make the model's own errors. Service.Do runs an operation in-process, and Service.Types, List, Get and Delete expose the stored resources by type for Cloud Control (cloudcontrol.go runs on them).

Statuses that move

A status that goes CREATING, then ACTIVE is worked out when a resource is read, so nothing runs in the background and a create never blocks. Derive registers a function that returns members of a resource type at read time; Step picks the state of a timed sequence (Begin starts or restarts one):

generic.Derive("mwaa", "Environment", func(r *generic.Resource) map[string]any {
	return map[string]any{"Status": generic.Step(r, "env", "CREATING", "AVAILABLE")}
})

Each state lasts SetLifecycleDelay long (1.5 seconds by default); tests set 0 to settle every resource at once, or an hour to freeze the first state.

A service whose signing name a hand-written service owns, and that is not Query, claims its requests with an entry in matchers (lambdamicrovms.go).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Begin

func Begin(r *Resource, key string)

Begin starts (or restarts) the timed sequence key of a resource now. Call it on a resource you then Put.

func CheckInput

func CheckInput(svc core.Service, c *core.Ctx, w http.ResponseWriter, r *http.Request) bool

CheckInput is core.Hub.CheckInput: it checks the limits of the input of a request to a hand-written AWS service before the service sees it, and answers a bad one with AWS's validation error. It reports whether it answered. A request it cannot parse is left to the service.

func Derive

func Derive(service, typ string, fn func(r *Resource) map[string]any)

Derive registers fn, which computes members of a service's resources of one type each time one is read (describe, list, create output). The members it returns, keyed by the model's names, win over the stored ones. See Step.

func Hook

func Hook(service, op string, fn func(*Call))

Hook runs fn after an operation succeeds, with c.Res set to the resource it created, updated or deleted (nil when it touched none): for side effects.

func OnClose

func OnClose(service string, fn func(s *Service))

OnClose runs fn when the hub shuts a service down (it stops a listener, forgets a store).

func Override

func Override(service, op string, fn func(*Call) (map[string]any, error))

Override replaces the behaviour of one operation of a service (the botocore directory name, e.g. "efs"). fn gets the parsed input and returns the output in member names; it may call c.Default() for the engine's own result and change it.

func Raw

func Raw(service string, fn func(s *Service, w http.ResponseWriter, r *http.Request) bool)

Raw lets a service answer requests that are not operations of its model (the Prometheus API of Managed Prometheus): fn reports whether it took the request. It runs before the request is matched to an operation.

func SetLifecycleDelay

func SetLifecycleDelay(d time.Duration) time.Duration

SetLifecycleDelay is the test hook: 0 settles every resource at once, a large value freezes it in its first state. It returns the previous value.

func Step

func Step(r *Resource, key string, states ...string) string

Step is where the timed sequence key of a resource is: states[0] when it began, then one state further per LifecycleDelay, and the last one for good. A sequence that was never begun started when the resource was created.

Types

type Call

type Call struct {
	Svc     *Service
	Op      string
	In      map[string]any // the input, keyed by the model's member names
	Core    *core.Ctx      // nil for Service.Do
	Account string
	Region  string
	Res     *Resource // set by the default behaviour

	// Stream, when an override sets it, writes the whole response itself (event streams).
	Stream func(http.ResponseWriter)
	// contains filtered or unexported fields
}

Call is one operation in flight, as an override or hook sees it.

func (*Call) Default

func (c *Call) Default() (map[string]any, error)

Default runs the engine's behaviour for the operation.

func (*Call) Err

func (c *Call) Err(shape, format string, a ...any) error

Err is the model's error shape of that name (with its code and HTTP status), for errors no pattern finds.

func (*Call) Exists

func (c *Call) Exists(format string, a ...any) error

func (*Call) Fill

func (c *Call) Fill(r *Resource) map[string]any

Fill builds an output the way the default behaviour does, from a resource (or nil).

func (*Call) Get

func (c *Call) Get(typ string, ids ...string) *Resource

Get returns a copy of the resource of a type whose identifiers (in the order of the type's identifier members) are ids, or nil.

func (*Call) Hub

func (c *Call) Hub() *core.Hub

Hub is the hub of the service, for cross-service calls.

func (*Call) Invalid

func (c *Call) Invalid(format string, a ...any) error

func (*Call) List

func (c *Call) List(typ string) []*Resource

List returns copies of the resources of a type in this account and region.

func (*Call) NotFound

func (c *Call) NotFound(format string, a ...any) error

NotFound, Exists and Invalid are the model's errors for those cases.

func (*Call) Put

func (c *Call) Put(r *Resource)

Put stores a resource changed by an override.

type Factory

type Factory struct {
	Name string
	New  func(*core.Hub) core.Service
}

Factory builds the service of one embedded model.

func Services

func Services() []Factory

Services returns a factory for every embedded model, sorted by name. The caller registers them after the hand-written services and skips names that already exist.

type Resource

type Resource struct {
	Type    string            `json:"type"`
	Key     string            `json:"key"` // the identifier values joined with "/"
	IDs     map[string]string `json:"ids,omitempty"`
	Name    string            `json:"name,omitempty"`
	ID      string            `json:"id,omitempty"`
	ARN     string            `json:"arn,omitempty"`
	Account string            `json:"account"`
	Region  string            `json:"region,omitempty"`
	Data    map[string]any    `json:"data,omitempty"`
	Tags    map[string]string `json:"tags,omitempty"`
	Created time.Time         `json:"created"`
	Updated time.Time         `json:"updated"`
}

Resource is one inferred resource: what its create and update calls sent, merged, plus its identifiers, tags and timestamps.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is one generated service. Its model is parsed on the first request.

func New

func New(h *core.Hub, name string) *Service

New makes the service for a model name (the botocore directory, e.g. "efs").

func (*Service) Close

func (s *Service) Close() error

Close stops the background work and runs the OnClose hooks; the hub calls it on shutdown.

func (*Service) Delete

func (s *Service) Delete(account, region, typ, key string) bool

Delete removes a resource by key and reports whether it existed.

func (*Service) Do

func (s *Service) Do(account, region, op string, in map[string]any) (map[string]any, error)

Do runs an operation in-process (no signature, chaos or IAM checks). The input uses the model's member names; the output does too.

func (*Service) Every

func (s *Service) Every(name string, d time.Duration, f func(now time.Time))

Every starts the background work of a service (budget alerts, report delivery) on a ticker, once per name. Tick runs it all once, for tests, and Close stops it.

func (*Service) Form

func (s *Service) Form(op string) *core.Form

Form builds the form of a create or update operation from its input shape.

func (*Service) FormOps

func (s *Service) FormOps() []string

FormOps lists the create and update operations of the service, sorted.

func (*Service) Get

func (s *Service) Get(account, region, typ, key string) *Resource

Get returns a copy of a resource by its key (identifiers joined with "/"), or nil.

func (*Service) Info

func (s *Service) Info() core.Info

func (*Service) Inspect

func (s *Service) Inspect(table, id string) any

Inspect returns the stored resource whose first-column id is id.

func (*Service) List

func (s *Service) List(account, region, typ string) []*Resource

List returns copies of the resources of a type.

func (*Service) Load

func (s *Service) Load(b []byte) error

func (*Service) Remove

func (s *Service) Remove(table, id string) error

Remove deletes the resource a console row shows through its type's delete operation.

func (*Service) Reset

func (s *Service) Reset()

func (*Service) Resources

func (s *Service) Resources() []core.Table

Resources lists the inferred resource types and their rows for the console.

func (*Service) Save

func (s *Service) Save() ([]byte, error)

func (*Service) SeedResource

func (s *Service) SeedResource(account, region, typ, key string, data map[string]any)

Seed stores a resource of a type under its key (the identifiers joined with "/"), replacing one that is there. data is in the model's member names, as the API returns it: it is how tests and seeding give a service something that no API call of its own can create (GetEntitlements has no create).

func (*Service) ServeHTTP

func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*Service) SupportsType

func (s *Service) SupportsType(typeName string) bool

SupportsType says whether Cloud Control manages a type through the engine of an embedded service (not through CloudFormation's own handlers). CloudFormation deploys such types the same way.

func (*Service) Tag

func (s *Service) Tag(table, id string, tags map[string]string) error

Tag adds tags to the resource a console row shows through the service's tag operation.

func (*Service) Tick

func (s *Service) Tick(now time.Time)

Tick runs the background work once as of now.

func (*Service) Types

func (s *Service) Types() []string

Types lists the inferred resource types.

Jump to

Keyboard shortcuts

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