Documentation
¶
Index ¶
- Constants
- func AdoptOwnedNode(path, serviceName, nodeID string, recordedAt time.Time, retire bool) error
- func CurrentRegistryFingerprint(path string) (string, error)
- func MarkOwnedNodeIDsRetired(path string, nodeIDs []string, retiredAt time.Time) error
- func RecordOwnedNode(path, serviceName, nodeID string, recordedAt time.Time) error
- func RegistryFingerprint(reg *registry.Registry, issues []registry.ServiceIssue) (string, error)
- func Remove(path string) error
- func RemoveOwnedNodeIDs(path string, nodeIDs []string) error
- func RemoveOwnedNodeIDsContext(ctx context.Context, path string, nodeIDs []string) error
- func RemoveServiceNodeState(configDir, name string) error
- func Save(path string, snapshot Snapshot) error
- func ServiceNodeStateConfigDir(registryPath string) string
- func TryRemoveOwnedNodesIfUnchanged(path string, oldNodes []OwnedNode) (bool, error)
- func TryUpdateOwnership(path string, update func(*OwnershipLedger) (bool, error)) (bool, error)
- func TryWithLockedOwnership(path string, fn func(OwnershipLedger) error) (bool, error)
- func UpdateOwnership(path string, update func(*OwnershipLedger) (changed bool, err error)) error
- func WithLockedOwnership(path string, fn func(OwnershipLedger) error) error
- func WithOwnershipLock(path string, fn func() error) error
- type ExpectedRuntime
- type Freshness
- type GatewayRouteState
- type GatewayState
- type OwnedNode
- type OwnershipLedger
- type PortalState
- type ServiceError
- type ServiceSnapshot
- type ServiceState
- type Snapshot
- type SnapshotError
- type SnapshotVersion
Constants ¶
const ( // SchemaVersion is the version of the runtime.json shape, the file the // daemon writes for the CLI. It is independent of the public view schema // (inspect.SchemaVersion), so a change to the public views never makes a // running daemon's snapshot unreadable to a newer CLI. Readers accept a // snapshot of this version and ignore fields they do not know: a daemon // may add fields without raising it, and raises it only for a shape an // older reader cannot read. SchemaVersion = 1 StatusExact = "exact" StatusMissing = "missing" StatusMalformed = "malformed" StatusUnreadable = "unreadable" StatusStale = "stale" StatusPartial = "partial" StatusPIDMismatch = "pid_mismatch" StatusRegistryMismatch = "registry_mismatch" ServiceRuntimeRunning = "running" ServiceRuntimeFailed = "failed" FunnelStateNotRequested = "not_requested" FunnelStateRequestedUnknown = "requested_unverified" FunnelStateActive = "active" FunnelStateCapabilityMissing = "capability_missing" FunnelStateListenFailed = "listen_failed" FunnelStateStartTimeout = "startup_timeout" )
const (
OwnershipSchemaVersion = 2
)
Variables ¶
This section is empty.
Functions ¶
func AdoptOwnedNode ¶
AdoptOwnedNode records a one-time reviewed proof for an exact device match. Orphans are retired immediately as explicit cleanup authorization; services still present in registry.json receive active proof without retired_at.
func CurrentRegistryFingerprint ¶
CurrentRegistryFingerprint fingerprints registry.json at path the way the daemon does, for comparison with the fingerprint in runtime.json.
func MarkOwnedNodeIDsRetired ¶
MarkOwnedNodeIDsRetired records that remove reviewed the exact ownership rows before unregistering their service. Rows remain until remote deletion succeeds or proves the device already absent.
func RecordOwnedNode ¶
RecordOwnedNode idempotently records exact NodeID ownership for a service.
func RegistryFingerprint ¶
RegistryFingerprint is the one derivation of the registry fingerprint: the daemon writes it into runtime.json and the CLI compares against it. Its input is every service entry registry.LoadForRuntime decodes, in file order, the valid ones and the ones isolated as per-service issues alike. The daemon passes what it loaded; the CLI calls CurrentRegistryFingerprint. A fingerprint over only the valid entries on one side would call a snapshot stale for as long as any service has an issue, which says nothing about whether the daemon applied the latest registry.
func RemoveOwnedNodeIDs ¶
RemoveOwnedNodeIDs forgets only ownership IDs that remote reconciliation has proved deleted or already absent.
func RemoveServiceNodeState ¶
RemoveServiceNodeState deletes the tsnet state directory a service kept inside configDir.
configDir is a parameter rather than something this function reads from the environment, and the callers derive it from the registry path they just wrote. That is what keeps the deletion inside the same config directory as the decision that authorised it: a caller operating on one registry while config.Dir() resolves to another would otherwise delete a live service's node identity out of an unrelated installation, and the deletion would look entirely normal from inside that caller.
The name is validated as a registry service name before anything is removed. Callers reach this with a name that came out of the ownership ledger or off a command line, and a registry service name is a DNS label -- no separator, no dot segment, no empty string -- so the validation is what keeps a malformed or hostile name from turning a RemoveAll of one directory into a RemoveAll of the nodes directory itself, or of something beside it.
It is deliberately not a decision about *whether* removing the state is safe. That decision needs facts this package does not have (was the remote node actually deleted, is a tsnet server still holding the directory), so it stays with the callers that have them.
func ServiceNodeStateConfigDir ¶
ServiceNodeStateConfigDir maps a registry path to the config directory that owns it. Registry and node state are siblings by construction, so this is the one derivation both callers use.
func TryRemoveOwnedNodesIfUnchanged ¶
TryRemoveOwnedNodesIfUnchanged clears only the exact rows that were proved resolved before local cleanup. A newly recorded identity with the same ID must survive a writer arriving after the final state deletion.
func TryUpdateOwnership ¶
TryUpdateOwnership updates the ledger atomically without waiting for a writer. A busy lock leaves both the local state and its retry evidence unchanged.
func TryWithLockedOwnership ¶
func TryWithLockedOwnership(path string, fn func(OwnershipLedger) error) (bool, error)
TryWithLockedOwnership reports false on contention without invoking fn.
func UpdateOwnership ¶
func UpdateOwnership(path string, update func(*OwnershipLedger) (changed bool, err error)) error
UpdateOwnership loads the ledger under its lock and hands it to update, saving it afterwards when update reports a change. What update reads, and any action it takes on that basis, happens before any other writer can change the ledger.
func WithLockedOwnership ¶
func WithLockedOwnership(path string, fn func(OwnershipLedger) error) error
WithLockedOwnership keeps a read and its local-state action atomic with RecordOwnedNode and RemoveOwnedNodeIDs. The callback must not write the ownership ledger or acquire this lock again.
func WithOwnershipLock ¶
WithOwnershipLock runs fn while holding the ledger's lock, the lock every ledger writer in this package takes in every process. A decision fn makes cannot be overtaken by a RecordOwnedNode, MarkOwnedNodeIDsRetired or RemoveOwnedNodeIDs. The lock is not reentrant: fn must not call those writers, or UpdateOwnership.
Types ¶
type ExpectedRuntime ¶
type Freshness ¶
type GatewayRouteState ¶ added in v0.2.0
type GatewayRouteState struct {
HealthChecked *time.Time `json:"health_checked,omitempty"`
App string `json:"app"`
Port int `json:"port"`
URL string `json:"url,omitempty"`
State string `json:"state"`
Reason string `json:"reason,omitempty"`
HostLabel string `json:"host_label"`
Health string `json:"health,omitempty"`
OfflineSince *time.Time `json:"offline_since,omitempty"`
}
type GatewayState ¶ added in v0.2.0
type GatewayState struct {
Dropped uint64 `json:"dropped"`
Enabled bool `json:"enabled"`
Persistent bool `json:"persistent"`
Tagged bool `json:"tagged"`
NodeID string `json:"node_id,omitempty"`
OwnershipProven bool `json:"ownership_proven"`
IdentityChanged bool `json:"identity_changed,omitempty"`
Ports registry.GatewayPorts `json:"ports"`
Routes []GatewayRouteState `json:"routes"`
}
type OwnedNode ¶
type OwnedNode struct {
ServiceName string `json:"service_name"`
NodeID string `json:"node_id"`
RecordedAt time.Time `json:"recorded_at"`
RetiredAt *time.Time `json:"retired_at,omitempty"`
}
OwnedNode is durable proof that a concrete Tailscale StableNodeID was observed from a TSLink-managed tsnet node for ServiceName.
func RetireServiceNodes ¶
func RetireServiceNodes(path, serviceName string, retiredAt time.Time, commit func() error) ([]OwnedNode, error)
RetireServiceNodes records the removal of serviceName in the same step as the removal itself. Holding the ledger lock, it marks every row of the service retired and then runs commit, the registry write that unregisters the service; when commit fails the ledger is put back exactly as it was. It returns the service's rows as they were before retirement.
The rows are the ones the ledger holds at that moment, not a snapshot taken before the caller waited for the registry lock: RecordOwnedNode takes the same ledger lock, so a node that enrolled for the service while the removal waited is retired with the others instead of keeping a row without retired_at, which would withhold its device deletion for good.
type OwnershipLedger ¶
type OwnershipLedger struct {
SchemaVersion int `json:"schema_version"`
Nodes []OwnedNode `json:"nodes"`
}
func LoadOwnership ¶
func LoadOwnership(path string) (OwnershipLedger, error)
LoadOwnership reads the durable ownership ledger. An absent or empty file is an empty ledger; malformed data returns an actionable coded error so callers can disable deletion without taking down service availability.
func PreviewAdoptOwnedNode ¶
func PreviewAdoptOwnedNode(path, serviceName, nodeID string, recordedAt time.Time, retire bool) (OwnershipLedger, error)
PreviewAdoptOwnedNode returns the exact proof that adoption would persist, without writing the ledger. retire is true only for a service absent from the registry, allowing cleanup dry-run to preview the corresponding deletion.
type PortalState ¶
type PortalState struct {
Message string `json:"message,omitempty"`
Gateway *GatewayState `json:"gateway,omitempty"`
Enabled bool `json:"enabled"`
Hostname string `json:"hostname,omitempty"`
State string `json:"state"`
URL string `json:"url,omitempty"`
Error string `json:"error,omitempty"`
}
PortalState is runtime evidence for the independent Tailnet portal node.
type ServiceError ¶
type ServiceError struct {
Code string `json:"code"`
Message string `json:"message"`
Next []string `json:"next,omitempty"`
Provision *registry.ProvisionOutcome `json:"provision,omitempty"`
}
ServiceError is stable, actionable failure data persisted for agent consumers.
type ServiceSnapshot ¶
type ServiceSnapshot struct {
Health health.State `json:"health"`
NodeKey health.Expiry `json:"node_key"`
Warnings []inspect.WarningView `json:"warnings,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
NodeID string `json:"node_id,omitempty"`
RuntimeState string `json:"runtime_state"`
Endpoint inspect.EndpointView `json:"endpoint"`
Exposure inspect.ExposureView `json:"exposure"`
FunnelRequested bool `json:"funnel_requested"`
FunnelActive bool `json:"funnel_active"`
FunnelState string `json:"funnel_state"`
Error *ServiceError `json:"error,omitempty"`
CertDomains []string `json:"cert_domains,omitempty"`
}
type ServiceState ¶
type Snapshot ¶
type Snapshot struct {
AccessLog *accesslog.Health `json:"access_log,omitempty"`
Portal PortalState `json:"portal"`
Alerts health.AlertsView `json:"alerts"`
SchemaVersion SnapshotVersion `json:"schema_version"`
DaemonPID int `json:"daemon_pid"`
DaemonStartedAt time.Time `json:"daemon_started_at"`
RegistryFingerprint string `json:"registry_fingerprint"`
UpdatedAt time.Time `json:"updated_at"`
Partial bool `json:"partial,omitempty"`
GlobalError *ServiceError `json:"global_error,omitempty"`
Services []ServiceSnapshot `json:"services"`
}
func NewPartialSnapshot ¶
func NewPartialSnapshot(daemonPID int, daemonStartedAt time.Time, registryFingerprint string, updatedAt time.Time, states []ServiceState) Snapshot
NewPartialSnapshot returns non-authoritative progress evidence produced while a registry synchronization is still starting services. Consumers may use services present in it as positive evidence, but absence is not evidence that any other registered service is down or missing.
func NewSnapshot ¶
type SnapshotError ¶
func (*SnapshotError) Error ¶
func (e *SnapshotError) Error() string
func (*SnapshotError) StableCode ¶
func (e *SnapshotError) StableCode() string
func (*SnapshotError) Unwrap ¶
func (e *SnapshotError) Unwrap() error
type SnapshotVersion ¶
type SnapshotVersion int
SnapshotVersion is runtime.json's schema_version. It reads the string that builds before the integer version wrote as version 1.
func (*SnapshotVersion) UnmarshalJSON ¶
func (v *SnapshotVersion) UnmarshalJSON(data []byte) error