Documentation
¶
Overview ¶
Package migration provides integration with Flyway for database migrations
Index ¶
- Constants
- Variables
- func PGRoleProvisioningSQL(spec *PGRoleSpec) ([]string, error)
- func ProvisionPGRoles(ctx context.Context, db *sql.DB, spec *PGRoleSpec) error
- type Action
- type AuditContext
- type AuditEvent
- type AuditEventType
- type AuditOutcome
- type AuditRecorder
- type Config
- type ErrorClass
- type FlywayMigrator
- func (fm *FlywayMigrator) Close(ctx context.Context) error
- func (fm *FlywayMigrator) DefaultMigrationConfig() *Config
- func (fm *FlywayMigrator) DefaultMigrationConfigForVendor(vendor string) *Config
- func (fm *FlywayMigrator) Info(ctx context.Context, cfg *Config) error
- func (fm *FlywayMigrator) InfoFor(ctx context.Context, db *config.DatabaseConfig, cfg *Config) error
- func (fm *FlywayMigrator) Migrate(ctx context.Context, cfg *Config) (Result, error)
- func (fm *FlywayMigrator) MigrateFor(ctx context.Context, db *config.DatabaseConfig, cfg *Config) (Result, error)
- func (fm *FlywayMigrator) RunMigrationsAtStartup(ctx context.Context) error
- func (fm *FlywayMigrator) Validate(ctx context.Context, cfg *Config) error
- func (fm *FlywayMigrator) ValidateFor(ctx context.Context, db *config.DatabaseConfig, cfg *Config) error
- func (fm *FlywayMigrator) WithAuditRecorder(sink AuditRecorder) *FlywayMigrator
- type MigrateAllOptions
- type MigrateAllResult
- type PGRoleSpec
- type Result
- type SecretFetcher
- type SecretsProvider
- type TenantLister
- type TenantResult
Constants ¶
const DefaultSecretsPrefix = "gobricks/migrate/"
DefaultSecretsPrefix is the default name prefix used to look up tenant database credentials in a secret store. The full secret name is DefaultSecretsPrefix + tenantID.
const PrincipalUnspecified = "<unspecified>"
PrincipalUnspecified is the sentinel emitted when an operator does not supply AppliedByPrincipal. The audit event still fires (so the gap is itself auditable) and the emitter logs a warning. Operators MUST pass an explicit principal in well-behaved callers; the framework refuses to invent one from IAM/OS context per ADR-019.
Variables ¶
var ErrEmptyTenantID = errors.New("migration: tenantID is empty")
ErrEmptyTenantID is returned when DBConfig is invoked with a blank tenant ID.
var ErrEnvFieldHasControlChar = errors.New("migration: env field contains forbidden control character (CR/LF/NUL)")
ErrEnvFieldHasControlChar is returned when a DatabaseConfig field destined for the Flyway subprocess environment contains a forbidden control character (CR, LF, or NUL). Go's exec.Cmd.Env passes strings to execve(2) verbatim and does not split on newlines, so this isn't a known injection path — but rejecting at the boundary prevents a compromised secret writer from propagating multi-line surprises into downstream logs or env-parsing tools.
var ErrInvalidPGIdentifier = errors.New("migration: PostgreSQL identifier rejected")
ErrInvalidPGIdentifier is returned by Validate when a role or schema name fails the safe-identifier check enforced by ProvisionPGRoles.
var ErrInvalidPrefix = errors.New("migration: invalid secrets prefix (must end with '/')")
ErrInvalidPrefix indicates the configured prefix is unusable.
var ErrInvalidTenantID = errors.New("migration: tenantID contains characters outside [A-Za-z0-9_-] or exceeds 128 characters")
ErrInvalidTenantID is returned when DBConfig is invoked with a tenant ID that contains characters outside the [A-Za-z0-9_-] allowlist or exceeds the 128-character length bound.
var ErrNoConfigProvider = errors.New("migration: database.DBConfigProvider is nil")
ErrNoConfigProvider is returned when MigrateAll is called without a DBConfigProvider.
var ErrNoFetcher = errors.New("migration: SecretsProvider.Fetch is nil")
ErrNoFetcher indicates the SecretsProvider was constructed without a Fetch function.
var ErrNoLister = errors.New("migration: TenantLister is nil")
ErrNoLister is returned when MigrateAll is called without a TenantLister.
var ErrSecretMalformed = errors.New("migration: secret payload malformed")
ErrSecretMalformed indicates the secret payload could not be parsed into a usable DatabaseConfig in either canonical or RDS-rotation form.
Functions ¶
func PGRoleProvisioningSQL ¶ added in v0.32.0
func PGRoleProvisioningSQL(spec *PGRoleSpec) ([]string, error)
PGRoleProvisioningSQL returns the SQL statements that ProvisionPGRoles would execute for spec, in order. Use this when operators want to inspect or apply the provisioning manually via psql, or feed it into their own migration runner (Flyway, Liquibase) rather than the Go helper.
Returns ErrInvalidPGIdentifier when spec fails Validate. The returned slice does not include trailing semicolons; callers concatenating them into a single script should add separators themselves.
SECURITY: when spec.MigratorPassword or spec.RuntimePassword is non-empty, the returned statements include the password as an in-clear SQL literal (`ALTER ROLE "..." PASSWORD '<secret>'`). Treat the returned slice as a sensitive value: do not echo it to logs, CI build artifacts, or anywhere the original credential wouldn't be acceptable. Callers preparing scripts for review should redact the literal before persisting to disk.
func ProvisionPGRoles ¶ added in v0.32.0
ProvisionPGRoles applies the role-pair + schema described by spec to the PostgreSQL instance reachable via db. All statements are idempotent: a rerun against an already-provisioned tenant is a no-op, except that MigratorPassword / RuntimePassword (when non-empty) are reapplied on every call to support secret rotation.
db MUST be authenticated as a role with CREATEROLE plus the right to CREATE SCHEMA AUTHORIZATION <other> — typically the instance bootstrap superuser or a dedicated provisioner role granted those capabilities. The migrator and runtime roles created here cannot self-provision: they are denied SUPERUSER, CREATEDB, CREATEROLE, BYPASSRLS, and REPLICATION per the deliverables of #378.
PostgreSQL is not fully transactional across role + schema boundaries (CREATE ROLE in particular is not transactional), so a partial-progress failure can leak intermediate state. Callers should rerun the same spec to converge; the idempotent template makes that safe.
Types ¶
type Action ¶ added in v0.31.0
type Action int
Action selects which Flyway operation MigrateAll runs against each tenant.
type AuditContext ¶ added in v0.32.0
type AuditContext struct {
// Principal identifies who triggered the migration (operator username,
// service account name, pipeline identifier). Empty values emit with
// PrincipalUnspecified + a warning so the gap is itself auditable.
Principal string
// GitCommitSHA records the source-tree commit the migration was built
// from. Useful for correlating an audit event to a specific deployment.
GitCommitSHA string
// PipelineRunID is an opaque CI/CD run identifier (e.g. a GitHub
// Actions run ID, a Jenkins build number). Lets compliance reporting
// trace an audit event back to a pipeline run.
PipelineRunID string
// Target overrides the audit event's Target field. Defaults to the
// database name (db.Database) when empty. Useful for multi-tenant runs
// where the tenant ID is more informative for compliance correlation
// than the per-tenant schema name.
Target string
}
AuditContext groups the per-call audit fields that flow into every migration.applied event. Operators MUST supply Principal explicitly per ADR-019; GitCommitSHA, PipelineRunID, and Target are optional but strongly recommended for deployment-time runs.
type AuditEvent ¶ added in v0.32.0
type AuditEvent struct {
Type AuditEventType
Target string
AppliedByPrincipal string
StartedAt time.Time
CompletedAt time.Time
Outcome AuditOutcome
// Version is the Flyway version applied. Set on migration.applied.
Version string
// FromState / ToState describe a provisioning-state-machine transition.
// Set on state.transitioned.
FromState string
ToState string
// ErrorClass is set when Outcome == failed; one of the published
// constants above. Empty for success/skipped outcomes.
ErrorClass ErrorClass
// GitCommitSHA and PipelineRunID are optional but strongly recommended
// for deployment-time runs; sourced from explicit caller input.
GitCommitSHA string
PipelineRunID string
// Attributes is a free-form extension point for callsite-specific
// metadata. Keys SHOULD use dotted lowercase (e.g. "migration.vendor").
Attributes map[string]string
}
AuditEvent is the canonical payload that flows into both the OpenTelemetry emission path and the optional AuditRecorder. The two paths share this struct so schemas cannot drift. Backwards-compatible additions follow Go's struct-additive rules; removing a field is a breaking change.
Target is an opaque schema/database identifier (tenant ID or schema name) and MUST NOT be a DSN — credentials never appear in audit events.
type AuditEventType ¶ added in v0.32.0
type AuditEventType string
AuditEventType enumerates the four migration audit-event types defined by ADR-019. Engine-layer emission covers migration.applied; orchestrator-layer events (state.transitioned, quiesce.*) are emitted by their respective subsystems when those land (#379, #380).
const ( // AuditEventTypeMigrationApplied marks a Flyway migration application // (successful or failed) against a target. AuditEventTypeMigrationApplied AuditEventType = "migration.applied" // AuditEventTypeStateTransitioned marks a provisioning-state-machine // transition. Emitted by #379 (not in this PR). AuditEventTypeStateTransitioned AuditEventType = "state.transitioned" // AuditEventTypeQuiesceSet marks an operator setting the deployment // quiesce flag. Emitted by #380 (not in this PR). AuditEventTypeQuiesceSet AuditEventType = "quiesce.set" // AuditEventTypeQuiesceCleared marks an operator clearing the deployment // quiesce flag. Emitted by #380 (not in this PR). AuditEventTypeQuiesceCleared AuditEventType = "quiesce.cleared" )
type AuditOutcome ¶ added in v0.32.0
type AuditOutcome string
AuditOutcome is the terminal outcome of the audited operation.
const ( AuditOutcomeSuccess AuditOutcome = "success" AuditOutcomeFailed AuditOutcome = "failed" AuditOutcomeSkipped AuditOutcome = "skipped" )
type AuditRecorder ¶ added in v0.32.0
type AuditRecorder interface {
Record(ctx context.Context, event *AuditEvent) error
}
AuditRecorder is the opt-in delivery path described in ADR-019. When wired (typically via FlywayMigrator.WithAuditRecorder), every AuditEvent fires to Record after the OTel emission, on a separate goroutine with a bounded send queue.
Record receives a non-nil *AuditEvent — the pointer matches the framework convention for medium-sized event payloads (see outbox.OutboxPublisher). Implementations SHOULD treat the event as read-only; the framework does not synchronize concurrent reads if a sink decides to mutate.
The framework calls Record with a fresh background context that may be cancelled by FlywayMigrator.Close. Implementations SHOULD respect ctx.Done() for prompt cancellation, but the framework does not retry on the sink's behalf — sink owners requiring zero-loss audit must back their implementation with a durable buffer (Kafka commit-log, S3 staging, etc.).
Errors returned from Record are logged as warnings and increment the migration.audit.sink_failures counter; they do NOT abort the migration. This is a deliberate trade-off per ADR-019: audit must not block business work.
type Config ¶
type Config struct {
FlywayPath string // Path to the Flyway executable
ConfigPath string // Path to the configuration file
MigrationPath string // Path to migration scripts
Timeout time.Duration // Timeout for migration operations
Environment string // Environment (development, testing, production)
DryRun bool // Only validate, do not execute
// Audit carries the per-call audit-event context required by ADR-019.
// Populated by operators (CLI flags) or pipelines (env vars or library
// call argument). The framework will NOT infer Principal from IAM/OS
// context — empty values flow through with a warning log.
Audit AuditContext
}
Config configuration for migrations
type ErrorClass ¶ added in v0.32.0
type ErrorClass string
ErrorClass is a stable string from a published taxonomy that downstream alerting can pin on. ADR-019 publishes seven values; the list is additive (new classes are non-breaking; removing one is breaking). Set only when Outcome == failed; otherwise leave empty.
const ( // ErrorClassChecksumMismatch — Flyway detected an applied script was // modified after the fact. ErrorClassChecksumMismatch ErrorClass = "checksum_mismatch" // ErrorClassLockTimeout — could not acquire the advisory / DBMS_LOCK // within the configured timeout. ErrorClassLockTimeout ErrorClass = "lock_timeout" // ErrorClassSchemaHistoryCorrupt — flyway_schema_history is in an // inconsistent state. ErrorClassSchemaHistoryCorrupt ErrorClass = "schema_history_corrupt" // ErrorClassTargetNotReady — the state-machine target is not in a state // that allows migration. Set by the orchestrator (#379), not the engine. ErrorClassTargetNotReady ErrorClass = "target_not_ready" // ErrorClassTargetUnreachable — the target database refused, timed out, // or DNS-failed. ErrorClassTargetUnreachable ErrorClass = "target_unreachable" // ErrorClassQuiesceBlocked — the quiesce flag was set; the run aborted // before any Flyway work. Set by the orchestrator (#380), not the engine. ErrorClassQuiesceBlocked ErrorClass = "quiesce_blocked" // ErrorClassInternal is the catch-all for unclassified panics and // unexpected errors. ErrorClassInternal ErrorClass = "internal_error" )
type FlywayMigrator ¶
type FlywayMigrator struct {
// contains filtered or unexported fields
}
FlywayMigrator handles database migrations using Flyway
func NewFlywayMigrator ¶
func NewFlywayMigrator(cfg *config.Config, log logger.Logger) *FlywayMigrator
NewFlywayMigrator creates a new instance of the migrator with the always-on OpenTelemetry audit-emission path wired up. Call WithAuditRecorder to add an optional compliance-grade durable delivery path per ADR-019.
func (*FlywayMigrator) Close ¶ added in v0.32.0
func (fm *FlywayMigrator) Close(ctx context.Context) error
Close drains the optional AuditRecorder queue and tears down the audit consumer goroutine. Safe to call when no sink is configured. Honors ctx for shutdown deadline; events still in flight when ctx expires are silently dropped (their OTel emission already succeeded).
func (*FlywayMigrator) DefaultMigrationConfig ¶ added in v0.19.0
func (fm *FlywayMigrator) DefaultMigrationConfig() *Config
DefaultMigrationConfig returns the default configuration for migrations
func (*FlywayMigrator) DefaultMigrationConfigForVendor ¶ added in v0.31.0
func (fm *FlywayMigrator) DefaultMigrationConfigForVendor(vendor string) *Config
DefaultMigrationConfigForVendor returns the default migration config for the given database vendor (e.g. "postgresql", "oracle"). Used by multi-tenant migrations where each tenant may run a different vendor than the migrator's own cfg.Database.Type. Unknown vendors fall back to the migrator's configured Database.Type so the vendor string never reaches filesystem path interpolation unvalidated; if even that is unknown, an "unknown" segment is used so callers see an obvious error rather than a path-traversal artifact.
func (*FlywayMigrator) Info ¶
func (fm *FlywayMigrator) Info(ctx context.Context, cfg *Config) error
Info shows information about the status of migrations against the migrator's database.
func (*FlywayMigrator) InfoFor ¶ added in v0.31.0
func (fm *FlywayMigrator) InfoFor(ctx context.Context, db *config.DatabaseConfig, cfg *Config) error
InfoFor shows migration status for the supplied database.
func (*FlywayMigrator) Migrate ¶
Migrate executes pending migrations against the migrator's configured database. The Result carries the parsed per-target outcome; on parse failure it is zero-valued and the error return is authoritative.
func (*FlywayMigrator) MigrateFor ¶ added in v0.31.0
func (fm *FlywayMigrator) MigrateFor(ctx context.Context, db *config.DatabaseConfig, cfg *Config) (Result, error)
MigrateFor executes pending migrations against the supplied database. Used by multi-tenant migrations to target a tenant-specific DatabaseConfig. See Migrate for the Result contract.
func (*FlywayMigrator) RunMigrationsAtStartup ¶
func (fm *FlywayMigrator) RunMigrationsAtStartup(ctx context.Context) error
RunMigrationsAtStartup executes migrations automatically at application startup. The structured Result is discarded here; downstream consumers pick it up via the migration.applied audit event.
func (*FlywayMigrator) Validate ¶
func (fm *FlywayMigrator) Validate(ctx context.Context, cfg *Config) error
Validate validates migrations without executing them against the migrator's database.
func (*FlywayMigrator) ValidateFor ¶ added in v0.31.0
func (fm *FlywayMigrator) ValidateFor(ctx context.Context, db *config.DatabaseConfig, cfg *Config) error
ValidateFor validates migrations for the supplied database.
func (*FlywayMigrator) WithAuditRecorder ¶ added in v0.32.0
func (fm *FlywayMigrator) WithAuditRecorder(sink AuditRecorder) *FlywayMigrator
WithAuditRecorder registers an optional AuditRecorder for compliance-grade durable delivery alongside the always-on OpenTelemetry emission. Replaces any previously-configured sink. Returns the receiver for chaining.
Intended to be called once at startup. The sink runs on its own goroutine with a bounded send queue per ADR-019 — slow sinks cannot stall migrations, and sink errors are logged but do not abort the migration. Call Close to drain the queue on shutdown.
type MigrateAllOptions ¶ added in v0.31.0
type MigrateAllOptions struct {
// BaseConfig supplies Flyway timeout / paths. ConfigPath and
// MigrationPath are auto-resolved per vendor when zero.
BaseConfig *Config
// ContinueOnError keeps iterating after the first per-tenant failure.
// Default false (fail-fast).
ContinueOnError bool
// Parallelism caps concurrent tenant migrations. 0 or 1 = sequential.
// Implementation caps the value to a reasonable maximum to avoid
// connection storms.
Parallelism int
// Logger receives progress updates. May be nil.
Logger logger.Logger
// Hook is invoked after each tenant completes (success or failure).
// Useful for streaming progress to the CLI / CI logs. May be nil.
Hook func(TenantResult)
}
MigrateAllOptions tunes per-tenant execution.
type MigrateAllResult ¶ added in v0.31.0
type MigrateAllResult struct {
Action Action
Results []TenantResult
}
MigrateAllResult aggregates per-tenant results from a MigrateAll run.
func MigrateAll ¶ added in v0.31.0
func MigrateAll( ctx context.Context, migrator *FlywayMigrator, lister TenantLister, configs database.DBConfigProvider, action Action, opts MigrateAllOptions, ) (*MigrateAllResult, error)
MigrateAll lists tenants via lister, resolves each tenant's database config via configs (the existing database.DBConfigProvider abstraction), and runs the chosen Flyway action against every one. Sequential fail-fast unless opts say otherwise.
func (*MigrateAllResult) Failed ¶ added in v0.31.0
func (r *MigrateAllResult) Failed() []TenantResult
Failed returns only the tenant results whose Err is non-nil.
type PGRoleSpec ¶ added in v0.32.0
type PGRoleSpec struct {
// Schema is the per-tenant schema name (e.g. "tenant_a"). Owned by
// MigratorRole after provisioning.
Schema string
// MigratorRole owns Schema and is used exclusively by the migration runner.
// Must differ from RuntimeRole.
MigratorRole string
// MigratorPassword is optionally assigned to MigratorRole via ALTER ROLE
// PASSWORD on every call. Useful for the one-time bootstrap and for
// secret rotation. Leave empty when credentials are managed externally
// (e.g., the role is created out-of-band and password set via a
// privileged migration pipeline).
MigratorPassword string
// RuntimeRole is the per-tenant DML-only role consumed by the running
// service. Must differ from MigratorRole.
RuntimeRole string
// RuntimePassword is optionally assigned to RuntimeRole. Same semantics
// as MigratorPassword — passing it on every call makes secret rotation a
// no-op rerun.
RuntimePassword string
}
PGRoleSpec describes a PostgreSQL role-pair plus per-tenant schema for the migrator-vs-runtime role-separation model defined in issue #378.
Migrator role: owns the per-tenant schema, holds DDL privileges, used exclusively by the migration runner. Created with NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS NOREPLICATION so even a compromised migrator credential cannot escalate itself.
Runtime role: per-tenant LOGIN role granted only DML on the tenant schema. Does not own the schema, so PostgreSQL's default ownership model rejects ALTER/CREATE/DROP statements from this role without any explicit REVOKE. Granted SELECT/INSERT/UPDATE/DELETE on existing AND future tables via ALTER DEFAULT PRIVILEGES so subsequent migrations don't need per-script grants.
func (*PGRoleSpec) Validate ¶ added in v0.32.0
func (s *PGRoleSpec) Validate() error
Validate reports whether the spec's identifiers pass the safe-identifier check and the two roles differ. Returns ErrInvalidPGIdentifier wrapped with the offending field name (and value) on failure.
type Result ¶ added in v0.32.0
type Result struct {
// Operation is the Flyway verb. Empty on the error envelope.
Operation string
// Success is false whenever Flyway emitted an error envelope, even if
// the JSON parsed cleanly.
Success bool
// AppliedVersions enumerates the migration versions Flyway applied in
// this run, in the order Flyway reported them. Empty on no-op reruns.
AppliedVersions []string
// StartingVersion is the schema version before this run (Flyway's
// initialSchemaVersion). Empty when Flyway reported it as null —
// typically on the first migrate against a fresh schema.
StartingVersion string
// EndingVersion is the schema version after this run. Flyway reports
// targetSchemaVersion as null on no-op runs; the parser falls back to
// StartingVersion in that case so callers always see a usable terminus.
EndingVersion string
// DurationMillis is Flyway's totalMigrationTime in milliseconds.
DurationMillis int64
// FlywayVersion is the engine version that produced this result.
FlywayVersion string
// DatabaseType is Flyway's databaseType field ("PostgreSQL", "Oracle").
DatabaseType string
// ErrorCode is Flyway's errorCode on the failure envelope (e.g.
// "VALIDATE_ERROR" for a checksum mismatch). Empty when Success is true.
ErrorCode string
// ErrorMessage is the human-readable error message from Flyway when
// Success is false. May contain embedded newlines from Flyway.
ErrorMessage string
}
Result captures the structured outcome of a single Flyway migrate invocation, populated from the engine's -outputType=json output. Fields are best-effort: an empty Result is returned when the subprocess crashed before emitting JSON or the payload was malformed. Callers that need an authoritative pass/fail signal should still consult the error returned alongside the Result.
type SecretFetcher ¶ added in v0.31.0
SecretFetcher resolves an opaque secret name to its raw payload bytes. The framework stays decoupled from any specific cloud SDK; callers wire AWS Secrets Manager, HashiCorp Vault, or another store behind this seam.
type SecretsProvider ¶ added in v0.31.0
type SecretsProvider struct {
// Prefix is prepended to each tenant ID when composing the secret name.
// Empty defaults to DefaultSecretsPrefix at lookup time.
Prefix string
// Fetch resolves a secret name to its payload. Required.
Fetch SecretFetcher
// contains filtered or unexported fields
}
SecretsProvider implements database.DBConfigProvider on top of a SecretFetcher. It composes the secret name as Prefix + tenantID, fetches the bytes, and parses them as either the canonical go-bricks DatabaseConfig shape or the AWS-managed RDS rotation shape.
func (*SecretsProvider) DBConfig ¶ added in v0.31.0
func (p *SecretsProvider) DBConfig(ctx context.Context, tenantID string) (*config.DatabaseConfig, error)
DBConfig satisfies database.DBConfigProvider. Looks up the tenant's secret, parses the payload, and returns the resulting DatabaseConfig.
func (*SecretsProvider) SecretName ¶ added in v0.31.0
func (p *SecretsProvider) SecretName(tenantID string) string
SecretName composes the full secret name for the given tenant ID using the provider's prefix (or DefaultSecretsPrefix when unset).
func (*SecretsProvider) Validate ¶ added in v0.31.0
func (p *SecretsProvider) Validate() error
Validate checks that the provider is wired correctly. Callers may invoke it eagerly at startup; DBConfig also calls it lazily on first lookup so library callers who skip the explicit check still get a clear error before any tenant fetch.
type TenantLister ¶ added in v0.31.0
TenantLister enumerates the tenant IDs that should receive migrations. Implementations include the HTTP source (for control-plane APIs) and a static source backed by config.TenantStore.
type TenantResult ¶ added in v0.31.0
type TenantResult struct {
TenantID string
Vendor string
Err error
Duration time.Duration
// Result is the parsed Flyway outcome for ActionMigrate. Zero-valued
// for Validate / Info, or when Flyway crashed before emitting JSON.
Result Result
}
TenantResult captures the outcome of running an Action against one tenant.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package provisioning implements a durable, crash-recoverable state machine for dynamic per-tenant provisioning under the multi-tenant migration model defined in issue #379.
|
Package provisioning implements a durable, crash-recoverable state machine for dynamic per-tenant provisioning under the multi-tenant migration model defined in issue #379. |
|
testing
Package testing provides test utilities for the provisioning state machine.
|
Package testing provides test utilities for the provisioning state machine. |
|
source
|
|
|
http
Package http provides a TenantLister that pulls tenant IDs from a control-plane API conforming to the go-bricks pre-defined contract.
|
Package http provides a TenantLister that pulls tenant IDs from a control-plane API conforming to the go-bricks pre-defined contract. |
|
static
Package static provides a TenantLister that enumerates tenant IDs from a config-backed source (typically the YAML-driven multitenant.tenants block).
|
Package static provides a TenantLister that enumerates tenant IDs from a config-backed source (typically the YAML-driven multitenant.tenants block). |