service

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package service is what the AWS resource packages share: the ambient configuration, the Secrets Manager reads a credential needs, and the registry the provider finds each resource package through.

Internal because none of it is a part of the resources API. It exists so that resources/aws/datastore and resources/aws/cache can share what is common to every AWS resource without either importing the other, and without the provider having to import a package for a service the application does not use.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PasswordIn

func PasswordIn(raw string, ref resources.Ref) (string, error)

PasswordIn takes the password out of a secret, whichever shape it is held in.

A reference is an opaque id handed to whoever knows how to read it, and what comes back is taken either way:

  • a JSON object, from which the password field is read. AWS deployments create the secret in this shape to match an AWS-managed RDS secret, so the same rotation tooling works against either.
  • anything else, which is the password itself.

An object carrying no password is a secret of the wrong kind rather than a password that happens to look like JSON, for example one pointed at the cluster's master secret by mistake. Sending the whole object as the password would fail as a wrong password, which is the hardest thing to tell from a rotation that has not finished.

func RegionOf

func RegionOf(ctx context.Context, ref resources.Ref) (string, error)

RegionOf reads the region a deployment recorded for a resource, which is empty for everything it created for this application.

Empty is the application's own region, which is where everything a deployment created for it lives. A resource the blueprint declares as external carries one, since it may be anywhere and, for a bucket, its ARN cannot say where: an S3 bucket ARN has no region segment.

func RegisterBucket

func RegisterBucket(f Factory[bucket.Store])

RegisterBucket is called by resources/aws/bucket when it is linked.

func RegisterCache

func RegisterCache(f Factory[cache.Client])

RegisterCache is called by resources/aws/cache when it is linked.

func RegisterDatastore

func RegisterDatastore(f Factory[datastore.Client])

RegisterDatastore is called by resources/aws/datastore when it is linked.

func RegisterQueue

func RegisterQueue(f Factory[queue.Client])

RegisterQueue is called by resources/aws/queue when it is linked.

func RegisterReleaser

func RegisterReleaser(release func(context.Context) error)

RegisterReleaser is called by a resource package that holds a connection pool or a client worth giving back on shutdown.

func RegisterSQLDatabase

func RegisterSQLDatabase(f Factory[sqldb.Client])

RegisterSQLDatabase is called by resources/aws/sqldb when it is linked.

func RegisterTopic

func RegisterTopic(f Factory[topic.Client])

RegisterTopic is called by resources/aws/topic when it is linked.

func Release

func Release(ctx context.Context) error

Release gives back everything the linked resource packages hold.

Every releaser is called even when an earlier one fails: shutdown is the one time carrying on matters more than the error.

func Secret

func Secret(
	ctx context.Context, s *Session, f resources.Fields, literalSuffix, refSuffix string,
) (string, bool, error)

Secret returns a value the deployment either wrote down or left a reference to, and whether it found one.

A local session seeds the literal, where it is a fixed constant nobody needs to protect. A deployed resource has a generated credential living in a secret, and what is recorded is its id: the credential can rotate, and a copy in the parameter store would keep working right up until it silently did not.

Neither is an error when both are absent, since a cache with no auth configured is a legitimate thing to deploy. The caller decides whether it can do without one.

Types

type Builder

type Builder[T any] func(resources.Ref) (T, error)

A resource package registers what it can build, and the provider asks here rather than importing the package itself.

That indirection is the whole point of the split: a build links the AWS service clients for the resources the blueprint declares and no others, so an application with a data store and nothing else does not carry S3, SQS, SNS and a Redis client it never calls. `celerity-go generate` writes an import per resource kind for that reason.

One slot per kind rather than a map of any, so that the provider's methods stay typed and a registration that does not match is a compile error.

func Buckets

func Buckets(s *Session) (Builder[bucket.Store], error)

Buckets returns the builder the bucket package registered.

func Caches

func Caches(s *Session) (Builder[cache.Client], error)

Caches returns the builder the cache package registered.

func Datastores

func Datastores(s *Session) (Builder[datastore.Client], error)

Datastores returns the builder the datastore package registered.

func Queues

func Queues(s *Session) (Builder[queue.Client], error)

Queues returns the builder the queue package registered.

func SQLDatabases

func SQLDatabases(s *Session) (Builder[sqldb.Client], error)

SQLDatabases returns the builder the sqldb package registered.

func Topics

func Topics(s *Session) (Builder[topic.Client], error)

Topics returns the builder the topic package registered.

type ClientKey

type ClientKey struct {
	// Region the client sends to. Empty is the application's own, which is what
	// a deployment records for everything it created for this application.
	Region string
}

ClientKey is what a cached service client is built for.

A struct of one field rather than a region string, because what distinguishes two clients is already expected to grow: reaching a resource in another account by assuming a role there would key on the identity the client signs with as well, and that is a field here rather than a different cache.

func KeyFor

func KeyFor(ctx context.Context, ref resources.Ref) (ClientKey, error)

KeyFor is the cache key for the client a resource is reached with.

type Clients

type Clients[T any] struct {
	// contains filtered or unexported fields
}

Clients caches one service client per key, building each on first use.

A single client for the whole provider was enough while every resource was one a deployment created for this application, since those are all in the application's own region. A resource the blueprint declares as external may be elsewhere, and a service routes a request by the region the client was built for, so a client per region is what lets one application reach both.

Clients are safe to share and expensive enough to be worth building once, so the entry for a key, including a failure to build it, is what every later caller for that key gets.

func (*Clients[T]) Get

func (c *Clients[T]) Get(_ context.Context, key ClientKey, build func() (T, error)) (T, error)

Get returns the client for a key, building it on the first call for that key.

The build runs outside the lock, so a client that is slow to construct does not hold up a caller wanting a different region.

type Factory

type Factory[T any] func(*Session) Builder[T]

Factory makes a builder for one provider's session. A resource package registers this, and the provider calls it once, so a lazily built service client is shared by every handle of that kind.

type Lazy

type Lazy[T any] struct {
	// contains filtered or unexported fields
}

Lazy builds a value once, on first use, and hands the same one to everything after.

A service client is safe to share and expensive enough to be worth building once, but cannot be built before a context exists, so it cannot be built when the handle is taken.

func (*Lazy[T]) Get

func (l *Lazy[T]) Get(build func() (T, error)) (T, error)

Get builds the value on the first call and returns what that call produced on every one after.

type SecretsAPI

type SecretsAPI interface {
	GetSecretValue(
		context.Context, *secretsmanager.GetSecretValueInput, ...func(*secretsmanager.Options),
	) (*secretsmanager.GetSecretValueOutput, error)
}

SecretsAPI is what this package calls on Secrets Manager, which is one read.

type Session

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

Session is the ambient AWS configuration, loaded once and shared by every resource one provider builds.

Loading reads the environment and may reach the instance metadata service for credentials, which is worth paying for once rather than per resource.

func NewSession

func NewSession() *Session

NewSession returns a session that loads the ambient configuration on first use.

func NewSessionWith

func NewSessionWith(load func(context.Context) (aws.Config, error)) *Session

NewSessionWith returns a session that loads what the given function returns, for a test driving a provider with no AWS to reach.

func (*Session) Config

func (s *Session) Config(ctx context.Context) (aws.Config, error)

Config loads the ambient AWS configuration once.

The first caller's context is the one the load runs under, which is the same bargain the config provider makes: it happens on a handler's first use of any resource, and every later caller gets what that one loaded.

func (*Session) ConfigFor

func (s *Session) ConfigFor(ctx context.Context, region string) (aws.Config, error)

ConfigFor returns the ambient configuration with its region replaced, for a resource the deployment recorded somewhere other than where the application runs.

An empty region, which is what a deployment records for everything it created for this application, is the application's own. The credentials are the same either way: reaching a resource in another account is the far side granting this role through a resource policy rather than this process holding another account's keys.

func (*Session) SecretString

func (s *Session) SecretString(ctx context.Context, id string) (string, error)

SecretString reads one secret's string value.

Read directly rather than through the config package's own AWS provider: that reads a whole store of application configuration, and this is one credential belonging to a resource.

func (*Session) UseSecrets

func (s *Session) UseSecrets(api SecretsAPI)

UseSecrets stands Secrets Manager in, for a test reading a credential with no AWS to reach.

Jump to

Keyboard shortcuts

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