emulator

package
v1.222.0 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package emulator provides first-class support for cloud-API emulators — long-running container services (Floci, MiniStack, k3s, OpenBao, …) that stand in for AWS, GCP, Azure, Kubernetes, and select backing services during local development and testing.

A driver is a built-in emulator product: it supplies container defaults (image, ports, services) and turns a live container endpoint into a connection Profile (env vars, kubeconfig, Terraform provider fragment).

This core package is driver-agnostic: the concrete drivers live in the pkg/emulator/driver subpackage (and their profile builders in pkg/emulator/target), registering into this package's registry via RegisterDriver at init. Importing pkg/emulator/driver is what populates the registry.

Index

Constants

View Source
const (
	TargetAWS        = "aws"
	TargetGCP        = "gcp"
	TargetAzure      = "azure"
	TargetKubernetes = "kubernetes"
	TargetVault      = "vault"
	TargetRegistry   = "registry"
	TargetGit        = "git"
)

Emulator targets — what an emulator emulates. Derived from a driver's Target().

Variables

This section is empty.

Functions

func Drivers

func Drivers() []string

Drivers returns the registered driver names, sorted.

func InstanceDataDir

func InstanceDataDir(stack, name string) (string, error)

InstanceDataDir returns (creating it if needed) the host directory that backs an emulator instance's persisted state, under the XDG cache. It honors ATMOS_XDG_CACHE_HOME / XDG_CACHE_HOME. The returned directory is bind-mounted onto the driver's in-container data dir when persistence is enabled.

func LookupInstanceDataDir

func LookupInstanceDataDir(stack, name string) string

LookupInstanceDataDir resolves the host directory backing an emulator instance's persisted state WITHOUT creating it. Used by `reset`, which removes the directory.

func RegisterDriver

func RegisterDriver(d EmulatorDriver)

RegisterDriver adds a built-in driver to the registry. Called from the driver subpackage's init(). Last registration wins, allowing override in tests.

func RegisterProfileResolver

func RegisterProfileResolver(r ProfileResolver)

RegisterProfileResolver registers the process-wide emulator profile resolver used by the `!emulator` YAML function. Called at init by pkg/component/emulator.

func ResolveYAMLFunc

func ResolveYAMLFunc(atmosConfig *schema.AtmosConfiguration, args, currentStack string, stackInfo *schema.ConfigAndStacksInfo) (any, error)

ResolveYAMLFunc evaluates `!emulator <ref> <key>` where args is the string after the tag. <ref> is the emulator component name (resolved in currentStack); <key> is one of: endpoint|url, host, port, region, project, kubeconfig, or env.<VAR>.

Types

type ContainerDefaults

type ContainerDefaults struct {
	// Image is the default container image, e.g. "floci/floci:latest".
	Image string
	// Ports are the default container ports the emulator listens on.
	Ports []int
	// Services are the default emulated services (informational; may drive env).
	Services []string
	// Env are default container environment variables.
	Env map[string]string
	// Privileged runs the container in privileged mode. It is a driver property,
	// not user config: some emulators (k3s, which runs a nested Kubernetes) only
	// function privileged.
	Privileged bool
	// Command is the default container command/args (e.g. k3s must run `server`).
	Command []string
	// DataDir is the in-container path where the emulator persists its state
	// (e.g. "/data" for floci, "/var/lib/registry" for the registry). When
	// persistence is enabled (the default), the manager bind-mounts a host
	// directory under the XDG cache onto this path so state survives `down`/`up`.
	// Empty means the driver has no persistent state, so persistence is a no-op.
	DataDir string
	// HealthCheck is the driver's default container health check, so the emulator
	// is readiness-aware out of the box (and `up` can gate on it). The component's
	// `container.healthcheck` overrides it; nil means the driver ships no default
	// (e.g. vault, whose readiness is handled by its bootstrap). The shape mirrors
	// the container kind's healthcheck, reusing schema.ContainerHealthCheck.
	HealthCheck *schema.ContainerHealthCheck
	// Restart is the driver's default container restart policy. The component's
	// `container.restart` overrides it; nil means no default (runtime default `no`).
	Restart *schema.ContainerRestart
}

ContainerDefaults are the built-in container defaults a driver supplies. Every field is overridable in the component's `container:` block (the hooks model).

type EmulatorDriver

type EmulatorDriver interface {
	// Name is the driver identifier used as `driver:` in component config.
	Name() string
	// Target is what the driver emulates (aws|gcp|azure|kubernetes|vault|registry).
	Target() string
	// Defaults are the built-in container defaults (overridable in `container:`).
	Defaults() ContainerDefaults
	// Profile turns a live endpoint into a connection profile.
	Profile(ep *Endpoint) Profile
}

EmulatorDriver is a built-in emulator product (floci, k3s, openbao, …).

func ResolveDriver

func ResolveDriver(name string) (EmulatorDriver, error)

ResolveDriver returns the built-in driver registered for the given name.

type Endpoint

type Endpoint struct {
	// Target is what the emulator emulates: aws|gcp|azure|kubernetes|vault|registry.
	Target string
	// Host is the host the emulator is reachable on (typically "localhost").
	Host string
	// Ports maps a container port to its live host port.
	Ports map[int]int
	// Region is the cloud region (aws/gcp/azure), when configured.
	Region string
	// Project is the GCP project, when configured.
	Project string
	// Services are the enabled emulated services (informational; drives env/endpoints).
	Services []string
}

Endpoint is the live connection info for a running emulator container, resolved from the runtime's reported port bindings.

func (*Endpoint) Authority

func (e *Endpoint) Authority() string

Authority returns the live "host:port" (no scheme) for the primary host port, or "" when no port is bound. Used by targets whose env vars want a bare host:port (GCP emulator hosts, Azure endpoints, registries).

func (*Endpoint) HostPort

func (e *Endpoint) HostPort(containerPort int) (int, bool)

HostPort returns the live host port bound to the given container port, and whether a binding exists.

func (*Endpoint) PrimaryHostPort

func (e *Endpoint) PrimaryHostPort() (int, bool)

PrimaryHostPort returns the live host port bound to the lowest-numbered container port — the conventional "primary" endpoint for single-port emulators (e.g. Floci/LocalStack on 4566).

func (*Endpoint) URL

func (e *Endpoint) URL(scheme string) string

URL builds a scheme://host:port URL for the primary host port. Returns "" when no port is bound.

type Manager

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

Manager operates emulator containers over the container component lifecycle, using ComponentType "emulator" so discovery, labels, and naming are shared with the container kind. It does not process stacks; callers pass a resolved Spec.

func NewManager

func NewManager(runtimePref string, autoStart bool) *Manager

NewManager returns a Manager that detects the container runtime using the given preference ("docker"|"podman"|"") and Podman auto-start setting.

func (*Manager) Down

func (m *Manager) Down(ctx context.Context, stack, name string) error

Down stops and removes the emulator's container.

func (*Manager) Exec

func (m *Manager) Exec(ctx context.Context, stack, name string, command []string) error

Exec runs a command in the emulator container (interactive; defaults to a shell).

func (*Manager) Kubeconfig

func (m *Manager) Kubeconfig(ctx context.Context, stack, name string) ([]byte, error)

Kubeconfig harvests the admin kubeconfig from a running kubernetes-target emulator (k3s) and rewrites its server URL to the live host port so it works from the host. The embedded CA and client credentials are preserved verbatim — that kubeconfig IS the credential.

It polls until the kubeconfig is readable (k3s writes it shortly after the API port opens) or the timeout elapses, so callers invoked immediately after `emulator up` do not lose the readiness race.

func (*Manager) Logs

func (m *Manager) Logs(ctx context.Context, stack, name string, follow bool) error

Logs streams the emulator container's logs to the default data/UI channels.

func (*Manager) Ps

func (m *Manager) Ps(ctx context.Context, stack string) ([]Status, error)

Ps lists emulator containers (by canonical labels). When stack is non-empty it returns only that stack's emulators; an empty stack returns every emulator across all stacks (used by `atmos emulator list` without `--stack`).

func (*Manager) Reset

func (m *Manager) Reset(ctx context.Context, spec *Spec, stack, name string) error

Reset stops and removes the emulator's container, then wipes its persisted state directory under the XDG cache. The next `up` starts a fresh instance. The data directory is derived from stack+name alone, so reset works without resolving the driver or a running container.

func (*Manager) Resolve

func (m *Manager) Resolve(ctx context.Context, spec *Spec, stack, name string) (Endpoint, Profile, error)

Resolve discovers the running emulator and builds its connection profile. It is the seam consumed by auth identities and the !emulator YAML function.

func (*Manager) Up

func (m *Manager) Up(ctx context.Context, spec *Spec, stack, name string, env map[string]string) (Endpoint, error)

Up reconciles the emulator's long-lived container and returns its live endpoint. Host ports are auto-assigned (0) unless pinned, so concurrent emulators do not collide; the live ports are read back from the runtime.

func (*Manager) VaultToken

func (m *Manager) VaultToken(ctx context.Context, stack, name string) (string, error)

VaultToken harvests the dynamic root token from a running Vault/OpenBao emulator (the file-backed server records it in a bootstrap file under its data dir).

type Profile

type Profile struct {
	// Env is the SDK / Terraform / VAULT_ADDR / registry environment.
	Env map[string]string
	// Kubeconfig holds a materialized kubeconfig for kubernetes targets.
	Kubeconfig []byte
	// ResolverURL is the base endpoint for Atmos's internal AWS SDK (aws only).
	ResolverURL string
	// Provider is a Terraform provider-config fragment (endpoints + skip-flags +
	// creds) consumed by the provider-config contributor.
	Provider map[string]any
}

Profile is what a driver advertises for a live emulator. Consumers subscribe to the parts they need: auth identities take Env (and, for kubernetes, Kubeconfig); the AWS resolver takes ResolverURL; the provider-config contributor takes Provider.

type ProfileResolver

type ProfileResolver func(atmosConfig *schema.AtmosConfiguration, ref, currentStack string, stackInfo *schema.ConfigAndStacksInfo) (*Endpoint, *Profile, error)

ProfileResolver resolves a running emulator's live endpoint and connection profile for the `!emulator` YAML function, by component reference and stack.

It is implemented ABOVE this layer (it needs stack processing and the container runtime) and registered at init via RegisterProfileResolver, keeping pkg/emulator free of any stack-processing import (no cycle).

type RootlessConfig

type RootlessConfig struct {
	RunArgs []string
	Command []string
	Applies bool
}

RootlessConfig is the run-args/command a driver substitutes under a rootless runtime, and whether such an override applies.

type RootlessOverrider

type RootlessOverrider interface {
	// RootlessOverride returns the run-args (e.g. an entrypoint override) and the
	// container command to use under a rootless runtime, and whether such an
	// override exists (false → the rootful defaults are used in all runtimes).
	RootlessOverride() (runArgs, command []string, ok bool)
}

RootlessOverrider is an optional driver interface for emulators whose container must run differently under a rootless runtime. For example, k3s needs a cgroup-nesting entrypoint and the kubelet `KubeletInUserNamespace` feature flag that rootful runtimes don't require. The manager calls RootlessOverride only when it detects a rootless runtime; otherwise the driver's default (rootful) command runs. Drivers without a rootless variant simply don't implement it.

type Spec

type Spec struct {
	// Driver is the built-in driver kind, e.g. "floci/aws".
	Driver string
	// Cloud is the explicit target; optional, derived from the driver when empty.
	Cloud string
	// Region is the cloud region (aws/gcp/azure).
	Region string
	// Project is the GCP project.
	Project string
	// Services are the emulated services to enable (informational; may drive env).
	Services []string
	// Ephemeral, when set true, runs the emulator without persisting state: no
	// host directory is bind-mounted onto the driver's data dir, so all state is
	// lost on `down`. It is tri-state: nil (the default) means persist. The CLI
	// `--ephemeral` flag forces a throwaway instance for a single `up`.
	Ephemeral *bool
	// Container holds image/ports/mounts/env overrides for the emulator container.
	Container *schema.ContainerRunStep
}

Spec is the resolved, per-instance emulator component configuration, parsed from the (merged, templated) component section. The nested `container:` block reuses the container kind's ContainerRunStep so emulator and container config stay consistent. These are first-class component sections (siblings of `metadata`/`env`/`composition`), NOT nested under `vars`.

func FromComponentSection

func FromComponentSection(section map[string]any) (Spec, error)

FromComponentSection decodes a resolved component section into a Spec, reading the first-class top-level keys `driver`, `cloud`, `region`, `project`, `services`, and the nested `container:` block.

func (*Spec) ContainerPorts

func (s *Spec) ContainerPorts() ([]schema.ContainerPort, error)

ContainerPorts returns the effective container ports to publish: the explicit `container.ports` when set, otherwise the driver's default ports. Host ports are left at 0 (auto-assigned) unless explicitly pinned.

func (*Spec) DataDir

func (s *Spec) DataDir() (string, error)

DataDir returns the driver's in-container persistence path (e.g. "/app/data"). An empty string means the driver has no persistent state, so persistence is a no-op for it.

func (*Spec) DefaultCommand

func (s *Spec) DefaultCommand() ([]string, error)

DefaultCommand returns the driver's default container command/args (e.g. k3s must run `server`). It is empty for emulators that use the image's entrypoint.

func (*Spec) DefaultEnv

func (s *Spec) DefaultEnv() (map[string]string, error)

DefaultEnv returns the driver's default container environment variables (e.g. k3s requires a K3S_TOKEN to start). The resolved profile/component env is layered over these by the manager.

func (*Spec) EffectiveHealthCheck

func (s *Spec) EffectiveHealthCheck() (*container.HealthCheck, error)

EffectiveHealthCheck returns the runtime health check for the emulator: the component's `container.healthcheck` when set, otherwise the driver's default (nil → no health check). It reuses the container kind's mapping so the Compose `test` form and disable semantics are identical across kinds.

func (*Spec) EffectiveRestart

func (s *Spec) EffectiveRestart() (*container.RestartPolicy, error)

EffectiveRestart returns the runtime restart policy for the emulator: the component's `container.restart` when set, otherwise the driver's default (nil → the runtime default of `no`).

func (*Spec) HostRuntime

func (s *Spec) HostRuntime() bool

HostRuntime reports whether the emulator container needs access to the host container runtime (Docker-out-of-Docker), set via `container.runtime.host: true`. Used, for example, by the MiniStack driver's EKS service to spawn a k3s sibling.

func (*Spec) Image

func (s *Spec) Image() (string, error)

Image returns the effective container image: the explicit `container.image` when set, otherwise the driver's default image.

func (*Spec) PersistEnabled

func (s *Spec) PersistEnabled() bool

PersistEnabled reports whether the emulator should persist state across `down`/`up`. Persistence is on by default; only an explicit `ephemeral: true` (or the `--ephemeral` CLI flag) disables it.

func (*Spec) Privileged

func (s *Spec) Privileged() (bool, error)

Privileged reports whether the emulator container must run in privileged mode. This is a driver property (e.g. k3s runs a nested Kubernetes), not user config.

func (*Spec) ResolvedDriver

func (s *Spec) ResolvedDriver() (EmulatorDriver, error)

Driver resolves the registered driver for this spec.

func (*Spec) RootlessOverride

func (s *Spec) RootlessOverride() (RootlessConfig, error)

RootlessOverride returns the rootless run-args/command for the spec's driver when it defines one (e.g. k3s needs a cgroup-nesting entrypoint). Drivers without a rootless variant return Applies=false, so the rootful defaults are used in all runtimes.

func (*Spec) Target

func (s *Spec) Target() (string, error)

Target returns the effective target: the explicit `cloud` when set (validated against the driver), otherwise the driver's own Target().

func (*Spec) Validate

func (s *Spec) Validate() error

Validate checks that the spec names a registered driver and that an explicit cloud (if any) matches the driver's target. Abstract bases are skipped by the caller before Validate is reached.

type Status

type Status struct {
	Name   string
	Stack  string
	Image  string
	Status string
	ID     string
}

Status is one row of `atmos emulator ps` / `atmos emulator list`.

Directories

Path Synopsis
Package driver holds the built-in emulator drivers (floci, k3s, openbao, …).
Package driver holds the built-in emulator drivers (floci, k3s, openbao, …).
Package target holds the per-target connection-profile builders for emulator drivers: each turns a live emulator Endpoint into a Profile (SDK env vars, a Terraform provider fragment, or a kubeconfig placeholder).
Package target holds the per-target connection-profile builders for emulator drivers: each turns a live emulator Endpoint into a Profile (SDK env vars, a Terraform provider fragment, or a kubeconfig placeholder).

Jump to

Keyboard shortcuts

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