Documentation
¶
Index ¶
- Constants
- Variables
- func BuildAccessChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
- func BuildChecks(cfg *stream.Config, selected []Category, opts ...ConnOption) ([]Check, CleanupFunc)
- func BuildConnectivityChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
- func BuildReplicationChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
- func BuildResourcesChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
- func BuildSchemaChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
- func BuildSourceChecks(sourceURL string, opts ...SourceOption) ([]Check, CleanupFunc, error)
- type Builder
- type Category
- type Check
- type CheckResult
- type CheckStatus
- type CleanupFunc
- type ConnOption
- type ConnectivityCheck
- type DatabaseSizeCheck
- type Detailer
- type DialFunc
- type Finding
- type LookupFunc
- type PostgresRangeTypeCheck
- type PostgresVersionCheck
- type ProgressFunc
- type ReplicaIdentityCheck
- type ReplicationRoleAttrCheck
- type ReplicationSlotHeadroomCheck
- type Report
- type ReportPrinter
- type RunOption
- type SchemaExtensionCompatibilityCheck
- type SchemaTypeCompatibilityCheck
- type SnapshotConnectionsCheck
- type SourceOption
- type SourceSequenceSelectPrivilegesCheck
- type SourceSnapshotInstanceCheck
- type SourceTableSelectPrivilegesCheck
- type StatusReason
- type Summarizer
- type TargetCreateDBPrivilegeCheck
- type TargetCreateRolePrivilegeCheck
- type WAL2JSONCheck
- type WALLevelCheck
Constants ¶
const ( FindingIDConnectionFailed = "connection_failed" FindingIDConnectionPingFailed = "connection_ping_failed" FindingIDWALLevelNotLogical = "wal_level_not_logical" FindingIDReplicationSlotHeadroomExhausted = "replication_slot_headroom_exhausted" FindingIDReplicationRoleAttributeMissing = "replication_role_attribute_missing" FindingIDReplicaIdentityNoPrimaryKey = "replica_identity_no_primary_key" FindingIDReplicaIdentityNothing = "replica_identity_nothing" FindingIDReplicaIdentityIndexUnusable = "replica_identity_index_unusable" FindingIDReplicaIdentityUnknown = "replica_identity_unknown" FindingIDSourceTableSelectPrivilegeMissing = "source_table_select_privilege_missing" FindingIDSourceSequenceSelectPrivilegeMissing = "source_sequence_select_privilege_missing" FindingIDTargetCreateDBPrivilegeMissing = "target_createdb_privilege_missing" FindingIDTargetCreateRolePrivilegeMissing = "target_createrole_privilege_missing" FindingIDUnsupportedColumnType = "unsupported_column_type" FindingIDUnsupportedRangeType = "unsupported_range_type" FindingIDTargetExtensionMissing = "target_extension_missing" FindingIDSnapshotConnectionHeadroomInsufficient = "snapshot_connection_headroom_insufficient" FindingIDSourceMultipleInstances = "source_multiple_instances" FindingIDTargetVersionOlderThanSource = "target_version_older_than_source" )
Finding ids name the kind of problem a check reports, never the instance of it. An id is stable: once released it does not change, because consumers key metrics and their own copy on it. An id contains lowercase letters, digits and underscores only, so it can never carry a value read from the database under test.
Variables ¶
var Builders = []Builder{ {CategoryConnectivity, "connectivity", BuildConnectivityChecks}, {CategoryReplication, "replication", BuildReplicationChecks}, {CategoryAccess, "access", BuildAccessChecks}, {CategorySchema, "schema", BuildSchemaChecks}, {CategoryResources, "resources", BuildResourcesChecks}, }
Builders is the registry of category builders. Adding a new category = one Builder entry here + one flag declaration on checkCmd.
var ErrNilSnapshotData = errors.New("snapshot data configuration must not be nil")
ErrNilSnapshotData is returned by BuildSourceChecks when WithSnapshotData is given a nil configuration.
Functions ¶
func BuildAccessChecks ¶
func BuildAccessChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
BuildAccessChecks returns the access-preflight checks applicable to cfg, plus a cleanup function that closes the shared source connection.
func BuildChecks ¶
func BuildChecks(cfg *stream.Config, selected []Category, opts ...ConnOption) ([]Check, CleanupFunc)
BuildChecks returns the concrete checks for the selected categories, preserving the registration order in Builders, plus a single cleanup function that releases every category's resources. The returned cleanup is always non-nil; callers can defer it unconditionally. An empty selection runs every registered category. The connection options apply to every connection the resulting checks open.
func BuildConnectivityChecks ¶
func BuildConnectivityChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
BuildConnectivityChecks returns the connectivity checks applicable to cfg. A source check is added when a source postgres URL is configured; a target check is added when a postgres target is configured. Each check opens its own conn (to its own URL), so no shared cleanup is needed.
func BuildReplicationChecks ¶
func BuildReplicationChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
BuildReplicationChecks returns the replication-preflight checks applicable to cfg, plus a cleanup function that closes the shared source connection. Replication checks only apply when the source is configured with a replication slot.
func BuildResourcesChecks ¶
func BuildResourcesChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
BuildResourcesChecks returns the resource-capacity preflight checks that apply to cfg, plus a cleanup function that closes the shared source connection. The database-size report applies to any configured source. The snapshot connection-headroom check is added only when a data snapshot is configured, because it sizes snapshot_workers x table_workers against the source's max_connections.
func BuildSchemaChecks ¶
func BuildSchemaChecks(cfg *stream.Config, opts ...ConnOption) ([]Check, CleanupFunc)
BuildSchemaChecks returns the schema-preflight checks applicable to cfg, plus a cleanup function that closes the shared source (and, when the target is Postgres, target) connection. Schema checks cover every table pgstream reads (snapshot and replication), so they use the combined access table selection. The version check runs whenever a source is configured — reporting the source version alone (so it survives --source) and additionally comparing against the target when a Postgres target URL is configured. The range-type check is added when the target is Postgres; the extension check additionally needs the target URL to query the target.
func BuildSourceChecks ¶ added in v1.5.0
func BuildSourceChecks(sourceURL string, opts ...SourceOption) ([]Check, CleanupFunc, error)
BuildSourceChecks returns every preflight check that only needs a connection to the source Postgres, plus a cleanup function releasing the connections those checks share. It is the entry point for callers that want to validate a source without assembling a full stream.Config: connectivity, replication readiness, source read privileges, schema compatibility and snapshot capacity.
Checks that compare the source against a target (extension compatibility, range-type support, the target privilege checks) are excluded by construction, and postgres_version reports the source version alone.
The returned cleanup is always non-nil, including on error, so callers can defer it unconditionally.
Types ¶
type Builder ¶
type Builder struct {
Category Category
Flag string
Build func(*stream.Config, ...ConnOption) ([]Check, CleanupFunc)
}
Builder turns a stream.Config into the concrete checks for a category, plus an optional cleanup function that releases resources the checks share (e.g. a Postgres connection). The connection options apply to every connection those checks open. Each new category adds an entry to Builders and a matching CLI flag in cmd/root_cmd.go.
type Category ¶
type Category string
Category groups checks of the same concern so callers can opt in by category via CLI flags. New categories are added as new check sets land — see docs/migration_preflight_issue.md for the planned ones.
type Check ¶
Check is the minimal contract every preflight check must satisfy. Run returns the findings the check produced; a non-nil error means the check itself could not complete (distinct from finding a problem with the system under test).
type CheckResult ¶
type CheckResult struct {
Name string `json:"name"`
Status CheckStatus `json:"-"`
Reason StatusReason `json:"-"`
Findings []Finding `json:"findings"`
Err error `json:"-"`
Details map[string]any `json:"-"`
Summary string `json:"-"`
}
CheckResult bundles a check's name with whatever it produced. Status and Reason are derived by the engine: Status says which of the four outcomes the check reached, and Reason explains every status other than StatusOK.
func (CheckResult) MarshalJSON ¶
func (r CheckResult) MarshalJSON() ([]byte, error)
MarshalJSON renders Err as a string so the report is consumable from a non-Go process (the default error marshaling drops the message).
type CheckStatus ¶ added in v1.5.0
type CheckStatus string
CheckStatus is the outcome the engine derived for a check. The engine always derives it; a check never sets its own status.
const ( StatusOK CheckStatus = "ok" // ran, found nothing wrong StatusFindings CheckStatus = "findings" // ran, reported at least one finding StatusError CheckStatus = "error" // ran, could not complete StatusNotRun CheckStatus = "not_run" // never started, or cut off before it produced a result )
type CleanupFunc ¶
CleanupFunc releases any resources a builder set up (e.g. a shared Postgres connection). Builders return nil when there's nothing to clean up.
type ConnOption ¶ added in v1.5.0
type ConnOption func(*connOptions)
ConnOption configures every connection the checks a builder returns open, including the connections the exported snapshot probe opens. Supplying no option leaves the connections exactly as pgstream configures them.
func WithDialFunc ¶ added in v1.5.0
func WithDialFunc(dial DialFunc) ConnOption
func WithLookupFunc ¶ added in v1.5.0
func WithLookupFunc(lookup LookupFunc) ConnOption
type ConnectivityCheck ¶
type ConnectivityCheck struct {
Label string
URL string
// ConnOptions configure the connection the check opens. Optional. See
// WithDialFunc and WithLookupFunc for the contract they must keep.
ConnOptions []ConnOption
}
ConnectivityCheck verifies a Postgres URL accepts a connection and answers a ping. A connection or ping failure is reported as a finding (not a check error), since establishing connectivity is the purpose of the check.
func (*ConnectivityCheck) Name ¶
func (c *ConnectivityCheck) Name() string
type DatabaseSizeCheck ¶ added in v1.5.0
type DatabaseSizeCheck struct {
Source postgres.AcquireFunc
// contains filtered or unexported fields
}
DatabaseSizeCheck reports the on-disk size of the source database, so that a migration run records the size it worked against. No database size is wrong on its own, so the check is informational and never produces a finding. Note that pg_database_size covers the whole database, including indexes and bloat, while a data snapshot copies less.
func (*DatabaseSizeCheck) Details ¶ added in v1.5.0
func (c *DatabaseSizeCheck) Details() map[string]any
Details reports the size as a byte count, so that a JSON consumer can calculate with it. Summary renders that count for a reader.
func (*DatabaseSizeCheck) Name ¶ added in v1.5.0
func (c *DatabaseSizeCheck) Name() string
func (*DatabaseSizeCheck) Run ¶ added in v1.5.0
func (c *DatabaseSizeCheck) Run(ctx context.Context) ([]Finding, error)
func (*DatabaseSizeCheck) Summary ¶ added in v1.5.0
func (c *DatabaseSizeCheck) Summary() string
Summary renders the size for the human-readable report.
type Detailer ¶
Detailer is an optional interface. A Check implements it to attach structured, non-finding context to its result, for example the extensions it inspected. The engine calls Details after Run and puts the result in the JSON report only, under the "details" key.
type Finding ¶
type Finding struct {
ID string `json:"id"`
Title string `json:"title"`
Detail string `json:"detail"`
Message string `json:"message"`
}
Finding describes a single issue detected by a Check. Every finding is an error — a check that finds nothing wrong returns no findings at all.
ID and Title identify the kind of problem, not the instance of it. Neither carries data read from the database under test, so a consumer can count findings by ID and show Title as a heading for a kind it has never seen. Detail carries the specifics: the tables, the version, the setting value. Message is the single line the CLI prints.
type LookupFunc ¶ added in v1.5.0
LookupFunc resolves a host name to the addresses to try.
type PostgresRangeTypeCheck ¶
type PostgresRangeTypeCheck struct {
Source postgres.AcquireFunc
Selection stream.TableSelection
}
PostgresRangeTypeCheck verifies that every in-scope range/multirange column uses a range type pgstream's Postgres target writer can actually encode.
func (*PostgresRangeTypeCheck) Name ¶
func (c *PostgresRangeTypeCheck) Name() string
type PostgresVersionCheck ¶ added in v1.2.3
type PostgresVersionCheck struct {
Source postgres.AcquireFunc
Target postgres.AcquireFunc
// contains filtered or unexported fields
}
PostgresVersionCheck reports the source's PostgreSQL version and, when a target is configured, verifies the target runs a major version at least as new as the source. pgstream snapshots the source with pg_dump and restores it into the target; restoring a dump taken from a newer server into an older one is unsupported and can fail on syntax or catalog differences the older server doesn't understand. The gate is on the major version — a minor/patch difference within the same major does not block a restore.
Target is optional: when nil (e.g. source-only runs) the check is purely informational and surfaces just the source version via Details (source_version); when set it additionally surfaces target_version and reports a finding on an incompatible downgrade. Either way it is the single source of truth for version information in the report.
func (*PostgresVersionCheck) Details ¶ added in v1.2.3
func (c *PostgresVersionCheck) Details() map[string]any
Details exposes the source version, and the target version too when a target was compared, so the report records what was inspected regardless of outcome.
func (*PostgresVersionCheck) Name ¶ added in v1.2.3
func (c *PostgresVersionCheck) Name() string
func (*PostgresVersionCheck) Run ¶ added in v1.2.3
func (c *PostgresVersionCheck) Run(ctx context.Context) ([]Finding, error)
func (*PostgresVersionCheck) Summary ¶ added in v1.5.0
func (c *PostgresVersionCheck) Summary() string
Summary reports the version for the human-readable report. It reports the source version alone when there is no target, and both versions otherwise.
type ProgressFunc ¶
ProgressFunc is invoked just before each check runs. idx is 1-based. A check the engine does not start reports no progress.
type ReplicaIdentityCheck ¶
type ReplicaIdentityCheck struct {
Source postgres.AcquireFunc
Selection stream.TableSelection
}
ReplicaIdentityCheck verifies that every in-scope table has a REPLICA IDENTITY sufficient for logical replication of UPDATE/DELETE WAL events. Anything insufficient means those events would silently be skipped at run time. The check inspects only the tables that pass the user's include/exclude filter (TableSelection) so unrelated tables don't pollute the report.
func (*ReplicaIdentityCheck) Name ¶
func (c *ReplicaIdentityCheck) Name() string
type ReplicationRoleAttrCheck ¶
type ReplicationRoleAttrCheck struct {
Source postgres.AcquireFunc
}
ReplicationRoleAttrCheck verifies the current source role has the REPLICATION attribute, which is required to open a logical replication slot.
func (*ReplicationRoleAttrCheck) Name ¶
func (c *ReplicationRoleAttrCheck) Name() string
type ReplicationSlotHeadroomCheck ¶
type ReplicationSlotHeadroomCheck struct {
Source postgres.AcquireFunc
}
ReplicationSlotHeadroomCheck reports whether the source has at least one slot still available before max_replication_slots is reached.
func (*ReplicationSlotHeadroomCheck) Name ¶
func (c *ReplicationSlotHeadroomCheck) Name() string
type Report ¶
type Report struct {
Results []CheckResult `json:"results"`
}
Report is the outcome of running a set of checks.
func Run ¶
Run executes every check in order. A check returning an error does not stop the run; subsequent checks still execute and the error is captured in the report alongside the findings. When the caller's context is done, Run starts no further checks and records each remaining one as StatusNotRun.
func (Report) HasErrors ¶
HasErrors reports whether the run was anything other than clean: a check produced findings, a check failed to complete, or a check did not run. A check that did not run counts, because a report with missing checks is no evidence that the system is ready, and the CLI exit code must not claim it is. Callers that want only the checks which looked and objected must read the statuses in the report.
type ReportPrinter ¶
type ReportPrinter struct {
Report Report
}
ReportPrinter renders a Report for display. It satisfies the cmd-side printer contract (PrettyPrint string + json.Marshaler), so existing print(cmd, p) helpers can drive it without change. Flag-driven rendering options (NoColor, Verbose, …) will live on this struct.
func (ReportPrinter) MarshalJSON ¶
func (p ReportPrinter) MarshalJSON() ([]byte, error)
MarshalJSON delegates to the underlying Report so a printer marshals to the same shape as the data type it wraps.
func (ReportPrinter) PrettyPrint ¶
func (p ReportPrinter) PrettyPrint() string
PrettyPrint renders the report as a human-readable string.
type RunOption ¶
type RunOption func(*runOptions)
RunOption configures Run.
func WithCheckTimeout ¶ added in v1.5.0
WithCheckTimeout bounds each check with a context deadline, so one slow check cannot consume the whole of the caller's budget. A check that exceeds the bound is reported as StatusNotRun, because a caller-imposed bound is not a defect in the check, and the run continues with the next check. The default is no bound, which runs every check to completion.
The bound is the deadline the check is given, not a limit the engine enforces on its own: the engine runs each check to completion, one at a time. A check honours the bound by passing the context it is given to the work it does — every check in this package passes it to the driver, which is context-aware. A check that ignores its context still runs past the bound, and blocks the run while it does.
func WithProgress ¶
func WithProgress(fn ProgressFunc) RunOption
WithProgress installs a callback invoked before each check runs. Useful for updating a spinner or log line with "running X of N: <name>".
type SchemaExtensionCompatibilityCheck ¶
type SchemaExtensionCompatibilityCheck struct {
Source postgres.AcquireFunc
Target postgres.AcquireFunc
// contains filtered or unexported fields
}
SchemaExtensionCompatibilityCheck verifies that every extension installed on the source database is also installed on the Postgres target. pgstream replicates the schema and data of objects that depend on extensions (custom types, functions, operators, index access methods), but it never installs the extensions themselves. It reports the full set of source extensions it inspected via Details (source_extensions), regardless of the outcome.
func (*SchemaExtensionCompatibilityCheck) Details ¶
func (c *SchemaExtensionCompatibilityCheck) Details() map[string]any
Details exposes every extension installed on the source as a string array under source_extensions, so the report records what was inspected even when nothing is missing.
func (*SchemaExtensionCompatibilityCheck) Name ¶
func (c *SchemaExtensionCompatibilityCheck) Name() string
type SchemaTypeCompatibilityCheck ¶
type SchemaTypeCompatibilityCheck struct {
Source postgres.AcquireFunc
Selection stream.TableSelection
}
SchemaTypeCompatibilityCheck verifies that pgstream can decode every column of every in-scope table. A column type is considered supported when either pgx's static type map natively handles it, or pgstream adds its own handling on top of pgx (pgstreamSupportedTypes).
func (*SchemaTypeCompatibilityCheck) Name ¶
func (c *SchemaTypeCompatibilityCheck) Name() string
type SnapshotConnectionsCheck ¶
type SnapshotConnectionsCheck struct {
Source postgres.AcquireFunc
// Demand is the number of concurrent connections the snapshot will open at
// peak (snapshot_workers × table_workers).
Demand uint
}
SnapshotConnectionsCheck verifies the source Postgres has enough spare connection slots to serve the snapshot's peak concurrency (snapshot_workers × table_workers) on top of what is already in use, without exceeding max_connections. Non-superuser roles cannot use the slots reserved by superuser_reserved_connections, so those are excluded from the headroom.
func (*SnapshotConnectionsCheck) Name ¶
func (c *SnapshotConnectionsCheck) Name() string
type SourceOption ¶ added in v1.5.0
type SourceOption func(*sourceOptions)
SourceOption configures BuildSourceChecks.
func WithConnOptions ¶ added in v1.5.0
func WithConnOptions(opts ...ConnOption) SourceOption
func WithSnapshotData ¶ added in v1.5.0
func WithSnapshotData(cfg *pgsnapshotgenerator.Config) SourceOption
WithSnapshotData sets the data snapshot configuration that the snapshot-gated checks size themselves against: snapshot_connection_headroom compares snapshot_workers x table_workers against the source's max_connections, and source_snapshot_single_instance derives its probe count from the same product.
func WithSourceCategories ¶ added in v1.5.0
func WithSourceCategories(categories ...Category) SourceOption
WithSourceCategories restricts the run to the given categories, in the order they are registered in Builders. Omitting it runs every category.
type SourceSequenceSelectPrivilegesCheck ¶
type SourceSequenceSelectPrivilegesCheck struct {
Source postgres.AcquireFunc
Selection stream.TableSelection
}
SourceSequenceSelectPrivilegesCheck verifies that the source Postgres role can read every in-scope sequence pgstream may need to snapshot.
func (*SourceSequenceSelectPrivilegesCheck) Name ¶
func (c *SourceSequenceSelectPrivilegesCheck) Name() string
type SourceSnapshotInstanceCheck ¶ added in v1.2.2
type SourceSnapshotInstanceCheck struct {
Probe func(ctx context.Context, probes int) (missing int, err error)
Probes int
}
SourceSnapshotInstanceCheck verifies the source URL resolves to a single Postgres instance, which parallel data snapshotting requires. The data snapshot generator exports a transaction snapshot on one connection and imports it (SET TRANSACTION SNAPSHOT) on other connections; an exported snapshot is instance-local, so a load-balanced source (an Aurora/RDS reader endpoint, or a pooler spanning instances) that routes some connections to a different instance fails with `snapshot "…" does not exist`.
The probe is probabilistic (see ProbeExportedSnapshotVisibility): a run that happens to route every probe connection to the exporting instance reports no finding.
func (*SourceSnapshotInstanceCheck) Name ¶ added in v1.2.2
func (c *SourceSnapshotInstanceCheck) Name() string
type SourceTableSelectPrivilegesCheck ¶
type SourceTableSelectPrivilegesCheck struct {
Source postgres.AcquireFunc
Selection stream.TableSelection
}
SourceTableSelectPrivilegesCheck verifies that the source Postgres role can read every table pgstream may need to snapshot or replicate.
func (*SourceTableSelectPrivilegesCheck) Name ¶
func (c *SourceTableSelectPrivilegesCheck) Name() string
type StatusReason ¶ added in v1.5.0
type StatusReason string
StatusReason is a short machine-readable explanation of a status other than StatusOK.
const ( ReasonFindingsReported StatusReason = "findings_reported" // accompanies StatusFindings ReasonCheckError StatusReason = "check_error" // accompanies StatusError; the message is in Err ReasonCheckDeadlineExceeded StatusReason = "check_deadline_exceeded" // exceeded the bound set with WithCheckTimeout ReasonRunDeadlineExceeded StatusReason = "run_deadline_exceeded" // the caller's context expired ReasonRunCanceled StatusReason = "run_canceled" // the caller cancelled the context )
type Summarizer ¶ added in v1.5.0
type Summarizer interface {
Summary() string
}
Summarizer is an optional interface. A Check implements it to report one short line about what it observed, such as a size or a version. The engine calls Summary after Run and prints the result next to the check name in the human-readable report only.
type TargetCreateDBPrivilegeCheck ¶ added in v1.3.1
type TargetCreateDBPrivilegeCheck struct {
Target postgres.AcquireFunc
}
func (*TargetCreateDBPrivilegeCheck) Name ¶ added in v1.3.1
func (c *TargetCreateDBPrivilegeCheck) Name() string
type TargetCreateRolePrivilegeCheck ¶ added in v1.4.0
type TargetCreateRolePrivilegeCheck struct {
Target postgres.AcquireFunc
}
func (*TargetCreateRolePrivilegeCheck) Name ¶ added in v1.4.0
func (c *TargetCreateRolePrivilegeCheck) Name() string
type WAL2JSONCheck ¶
type WAL2JSONCheck struct {
Source postgres.AcquireFunc
}
WAL2JSONCheck verifies that the wal2json output plugin is installed and loadable on the source. pgstream decodes WAL through wal2json.
wal2json is a logical-decoding output plugin, not a SQL extension, so it never appears in pg_available_extensions and there is no catalog that lists installed output plugins. The only way to detect it with pgstream's privileges (a non-superuser REPLICATION role) is to probe actual behaviour: create a temporary logical replication slot with the plugin and inspect the outcome. The temporary slot is released automatically at session end, and is dropped explicitly on success so it never counts against slot headroom.
func (*WAL2JSONCheck) Name ¶
func (c *WAL2JSONCheck) Name() string
type WALLevelCheck ¶
type WALLevelCheck struct {
Source postgres.AcquireFunc
}
WALLevelCheck verifies the source Postgres has `wal_level=logical`, which pgstream's replication path requires.
func (*WALLevelCheck) Name ¶
func (c *WALLevelCheck) Name() string