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 ¶
- Add the botocore directory name (the one under botocore/data) to services.txt.
- 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.
- 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.
- 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 ¶
- func Begin(r *Resource, key string)
- func CheckInput(svc core.Service, c *core.Ctx, w http.ResponseWriter, r *http.Request) bool
- func Derive(service, typ string, fn func(r *Resource) map[string]any)
- func Hook(service, op string, fn func(*Call))
- func OnClose(service string, fn func(s *Service))
- func Override(service, op string, fn func(*Call) (map[string]any, error))
- func Raw(service string, ...)
- func SetLifecycleDelay(d time.Duration) time.Duration
- func Step(r *Resource, key string, states ...string) string
- type Call
- func (c *Call) Default() (map[string]any, error)
- func (c *Call) Err(shape, format string, a ...any) error
- func (c *Call) Exists(format string, a ...any) error
- func (c *Call) Fill(r *Resource) map[string]any
- func (c *Call) Get(typ string, ids ...string) *Resource
- func (c *Call) Hub() *core.Hub
- func (c *Call) Invalid(format string, a ...any) error
- func (c *Call) List(typ string) []*Resource
- func (c *Call) NotFound(format string, a ...any) error
- func (c *Call) Put(r *Resource)
- type Factory
- type Resource
- type Service
- func (s *Service) Close() error
- func (s *Service) Delete(account, region, typ, key string) bool
- func (s *Service) Do(account, region, op string, in map[string]any) (map[string]any, error)
- func (s *Service) Every(name string, d time.Duration, f func(now time.Time))
- func (s *Service) Form(op string) *core.Form
- func (s *Service) FormOps() []string
- func (s *Service) Get(account, region, typ, key string) *Resource
- func (s *Service) Info() core.Info
- func (s *Service) Inspect(table, id string) any
- func (s *Service) List(account, region, typ string) []*Resource
- func (s *Service) Load(b []byte) error
- func (s *Service) Remove(table, id string) error
- func (s *Service) Reset()
- func (s *Service) Resources() []core.Table
- func (s *Service) Save() ([]byte, error)
- func (s *Service) SeedResource(account, region, typ, key string, data map[string]any)
- func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (s *Service) SupportsType(typeName string) bool
- func (s *Service) Tag(table, id string, tags map[string]string) error
- func (s *Service) Tick(now time.Time)
- func (s *Service) Types() []string
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Begin ¶
Begin starts (or restarts) the timed sequence key of a resource now. Call it on a resource you then Put.
func CheckInput ¶
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 ¶
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 ¶
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 ¶
OnClose runs fn when the hub shuts a service down (it stops a listener, forgets a store).
func Override ¶
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 ¶
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 ¶
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.
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) Err ¶
Err is the model's error shape of that name (with its code and HTTP status), for errors no pattern finds.
func (*Call) Fill ¶
Fill builds an output the way the default behaviour does, from a resource (or nil).
func (*Call) Get ¶
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.
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 (*Service) Close ¶
Close stops the background work and runs the OnClose hooks; the hub calls it on shutdown.
func (*Service) Do ¶
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 ¶
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) Get ¶
Get returns a copy of a resource by its key (identifiers joined with "/"), or nil.
func (*Service) Remove ¶
Remove deletes the resource a console row shows through its type's delete operation.
func (*Service) Resources ¶
Resources lists the inferred resource types and their rows for the console.
func (*Service) SeedResource ¶
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) SupportsType ¶
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 ¶
Tag adds tags to the resource a console row shows through the service's tag operation.
Source Files
¶
- accessanalyzer.go
- account.go
- acmpca.go
- ai.go
- amp.go
- amplify.go
- appflow.go
- backup.go
- bcmdataexports.go
- bcmpricingcalculator.go
- bedrock.go
- bedrockagent.go
- bedrockagentcore.go
- bedrockagentruntime.go
- bedrockruntime.go
- budgets.go
- ce.go
- cleanrooms.go
- cloudcontrol.go
- cloudhsmv2.go
- codecommit.go
- codestarconnections.go
- comprehend.go
- config.go
- connect.go
- containers.go
- controlcatalog.go
- controltower.go
- cost.go
- costmodel.go
- costoptimizer.go
- costreport.go
- cur.go
- datasync.go
- datazone.go
- dax.go
- detective.go
- directconnect.go
- dms.go
- doc.go
- drs.go
- ds.go
- dsql.go
- efs.go
- elasticbeanstalk.go
- elb.go
- emr.go
- emrserverless.go
- engine.go
- errors.go
- fill.go
- fms.go
- forms.go
- fsx.go
- gamelift.go
- grafana.go
- groupk.go
- identitystore.go
- imagebuilder.go
- inspector2.go
- ivs.go
- keyspaces.go
- kinesisanalyticsv2.go
- kinesisvideo.go
- lakeformation.go
- lambdamicrovms.go
- lifecycle.go
- lightsail.go
- limits.go
- location.go
- macie2.go
- marketplacecatalog.go
- marketplaceentitlement.go
- mediaconvert.go
- medialive.go
- meteringmarketplace.go
- model.go
- mwaa.go
- names.go
- networkfirewall.go
- networkmanager.go
- notifications.go
- oam.go
- odb.go
- ops.go
- paymentcryptography.go
- polly.go
- pricing.go
- ram.go
- rekognition.go
- resiliencehub.go
- resourcegroups.go
- route53resolver.go
- rum.go
- s2util.go
- s3tables.go
- sagemaker.go
- sagemakerruntime.go
- securityhub.go
- securitylake.go
- serverlessrepo.go
- servicequotas.go
- shield.go
- sso.go
- ssoadmin.go
- state.go
- storagegateway.go
- textract.go
- transcribe.go
- transfer.go
- translate.go
- vpclattice.go
- wafv2.go
- wire.go
- workspaces.go
- xray.go