Documentation
¶
Overview ¶
Package rsl (Runtime State Layer) bridges live cluster reality, persisted application state, and operator-supplied inputs into a single, deterministic effective value for every configurable field.
Core types ¶
Selector is the selection algorithm interface. A Selector receives the full sources map and returns the winning value together with the strategy that produced it. DefaultSelector provides the standard priority-walk implementation; custom Selectors encode field-specific rules such as validation, soft fall-through, or intent-aware logic.
EffectiveValue is the per-field container. It holds a sources map (keyed by automa.EffectiveStrategy), a Selector, and a lazily-computed cached result. Callers push values in via EffectiveValue.SetSource and pull the winner out via EffectiveValue.Get or EffectiveValue.Resolve.
Resolution precedence (highest → lowest) ¶
StrategyReality — live cluster state (from RefreshState) StrategyState — persisted state.yaml (from WithState) StrategyUserInput — CLI flags (from WithUserInputs) StrategyEnv — environment variable (set externally) StrategyConfig — config file (from WithConfig) StrategyDefault — hardcoded deps.* (seeded at construction) StrategyZero — zero value (ultimate fallback)
Lifecycle ¶
- Construct with NewEffectiveValue, passing a Selector. The sources map starts empty; call EffectiveValue.SetSource (or the With* methods on the owning resolver) to populate sources before resolving.
- Call EffectiveValue.SetSource / EffectiveValue.ClearSource as inputs arrive (config load, user flags, state refresh). Each mutation invalidates the cache.
- Call EffectiveValue.Resolve (or EffectiveValue.Get) to obtain the winning value. The result is cached until the next mutation.
- Use the source-specific accessors (EffectiveValue.StateVal, EffectiveValue.UserInputVal, etc.) to inspect individual layers without triggering resolution.
Index ¶
- Constants
- func StrategyName(s automa.EffectiveStrategy) string
- type BlockNodeRuntimeResolver
- func (b *BlockNodeRuntimeResolver) ChartName() (*EffectiveValue[string], error)
- func (b *BlockNodeRuntimeResolver) ChartRef() (*EffectiveValue[string], error)
- func (b *BlockNodeRuntimeResolver) ChartVersion() (*EffectiveValue[string], error)
- func (b *BlockNodeRuntimeResolver) CurrentState() (state.BlockNodeState, error)
- func (b *BlockNodeRuntimeResolver) HistoricRetention() (*EffectiveValue[string], error)
- func (b *BlockNodeRuntimeResolver) Namespace() (*EffectiveValue[string], error)
- func (b *BlockNodeRuntimeResolver) RecentRetention() (*EffectiveValue[string], error)
- func (b *BlockNodeRuntimeResolver) RefreshState(ctx context.Context, force bool) error
- func (b *BlockNodeRuntimeResolver) ReleaseName() (*EffectiveValue[string], error)
- func (b *BlockNodeRuntimeResolver) Storage() (*EffectiveValue[models.BlockNodeStorage], error)
- func (b *BlockNodeRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.BlockNodeState, models.BlockNodeInputs]
- func (b *BlockNodeRuntimeResolver) WithDefaults(cfg models.Config) Resolver[state.BlockNodeState, models.BlockNodeInputs]
- func (b *BlockNodeRuntimeResolver) WithEnv(cfg models.Config) Resolver[state.BlockNodeState, models.BlockNodeInputs]
- func (b *BlockNodeRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.BlockNodeState, models.BlockNodeInputs]
- func (b *BlockNodeRuntimeResolver) WithState(st state.BlockNodeState) Resolver[state.BlockNodeState, models.BlockNodeInputs]
- func (b *BlockNodeRuntimeResolver) WithUserInputs(inputs models.BlockNodeInputs) Resolver[state.BlockNodeState, models.BlockNodeInputs]
- type ClusterRuntimeResolver
- func (c *ClusterRuntimeResolver) CurrentState() (state.ClusterState, error)
- func (c *ClusterRuntimeResolver) RefreshState(ctx context.Context, force bool) error
- func (c *ClusterRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.ClusterState, models.ClusterInputs]
- func (c *ClusterRuntimeResolver) WithDefaults(_ models.Config) Resolver[state.ClusterState, models.ClusterInputs]
- func (c *ClusterRuntimeResolver) WithEnv(_ models.Config) Resolver[state.ClusterState, models.ClusterInputs]
- func (c *ClusterRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.ClusterState, models.ClusterInputs]
- func (c *ClusterRuntimeResolver) WithState(st state.ClusterState) Resolver[state.ClusterState, models.ClusterInputs]
- func (c *ClusterRuntimeResolver) WithUserInputs(inputs models.ClusterInputs) Resolver[state.ClusterState, models.ClusterInputs]
- type DefaultSelector
- type EffectiveValue
- func (e *EffectiveValue[T]) ClearSource(strategy automa.EffectiveStrategy)
- func (e *EffectiveValue[T]) ConfigVal() (automa.Value[T], error)
- func (e *EffectiveValue[T]) DefaultVal() (automa.Value[T], error)
- func (e *EffectiveValue[T]) EnvVal() (automa.Value[T], error)
- func (e *EffectiveValue[T]) Err() error
- func (e *EffectiveValue[T]) Get() automa.Value[T]
- func (e *EffectiveValue[T]) Invalidate()
- func (e *EffectiveValue[T]) MarshalJSON() ([]byte, error)
- func (e *EffectiveValue[T]) RealityVal() (automa.Value[T], error)
- func (e *EffectiveValue[T]) Resolve() (*automa.EffectiveValue[T], error)
- func (e *EffectiveValue[T]) SetSource(strategy automa.EffectiveStrategy, v T) error
- func (e *EffectiveValue[T]) StateVal() (automa.Value[T], error)
- func (e *EffectiveValue[T]) Strategy() automa.EffectiveStrategy
- func (e *EffectiveValue[T]) StrategyName() string
- func (e *EffectiveValue[T]) String() string
- func (e *EffectiveValue[T]) UserInputVal() (automa.Value[T], error)
- func (e *EffectiveValue[T]) ValOf(sourceStrategy automa.EffectiveStrategy) automa.Value[T]
- func (e *EffectiveValue[T]) WithSelector(selector Selector[T])
- func (e *EffectiveValue[T]) ZeroVal() automa.Value[T]
- type MachineRuntimeResolver
- func (m *MachineRuntimeResolver) CurrentState() (state.MachineState, error)
- func (m *MachineRuntimeResolver) RefreshState(ctx context.Context, force bool) error
- func (m *MachineRuntimeResolver) SoftwareState(name string) (state.SoftwareState, bool)
- func (m *MachineRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.MachineState, models.MachineInputs]
- func (m *MachineRuntimeResolver) WithDefaults(_ models.Config) Resolver[state.MachineState, models.MachineInputs]
- func (m *MachineRuntimeResolver) WithEnv(_ models.Config) Resolver[state.MachineState, models.MachineInputs]
- func (m *MachineRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.MachineState, models.MachineInputs]
- func (m *MachineRuntimeResolver) WithState(st state.MachineState) Resolver[state.MachineState, models.MachineInputs]
- func (m *MachineRuntimeResolver) WithUserInputs(inputs models.MachineInputs) Resolver[state.MachineState, models.MachineInputs]
- type Resolver
- func NewBlockNodeRuntimeResolver(cfg models.Config, blockNodeState state.BlockNodeState, ...) (Resolver[state.BlockNodeState, models.BlockNodeInputs], error)
- func NewClusterRuntimeResolver(cfg models.Config, clusterState state.ClusterState, ...) (Resolver[state.ClusterState, models.ClusterInputs], error)
- func NewMachineRuntimeResolver(cfg models.Config, clusterState state.MachineState, ...) (Resolver[state.MachineState, models.MachineInputs], error)
- func NewTeleportRuntimeResolver(cfg models.Config, teleportState state.TeleportState, ...) (Resolver[state.TeleportState, models.TeleportNodeInputs], error)
- type RuntimeResolver
- type Selector
- type TeleportRuntimeResolver
- func (t *TeleportRuntimeResolver) CurrentState() (state.TeleportState, error)
- func (t *TeleportRuntimeResolver) Namespace() (*EffectiveValue[string], error)
- func (t *TeleportRuntimeResolver) ProxyAddr() (*EffectiveValue[string], error)
- func (t *TeleportRuntimeResolver) RefreshState(ctx context.Context, force bool) error
- func (t *TeleportRuntimeResolver) ReleaseName() (*EffectiveValue[string], error)
- func (t *TeleportRuntimeResolver) Token() (*EffectiveValue[string], error)
- func (t *TeleportRuntimeResolver) ValuesFile() (*EffectiveValue[string], error)
- func (t *TeleportRuntimeResolver) Version() (*EffectiveValue[string], error)
- func (t *TeleportRuntimeResolver) WithClusterInputs(inputs models.TeleportClusterInputs) *TeleportRuntimeResolver
- func (t *TeleportRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.TeleportState, models.TeleportNodeInputs]
- func (t *TeleportRuntimeResolver) WithDefaults(cfg models.Config) Resolver[state.TeleportState, models.TeleportNodeInputs]
- func (t *TeleportRuntimeResolver) WithEnv(cfg models.Config) Resolver[state.TeleportState, models.TeleportNodeInputs]
- func (t *TeleportRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.TeleportState, models.TeleportNodeInputs]
- func (t *TeleportRuntimeResolver) WithState(st state.TeleportState) Resolver[state.TeleportState, models.TeleportNodeInputs]
- func (t *TeleportRuntimeResolver) WithUserInputs(inputs models.TeleportNodeInputs) Resolver[state.TeleportState, models.TeleportNodeInputs]
Constants ¶
const ( // StrategyZero is the ultimate fallback returned when no source supplies a // value. The associated value is always the zero value of T. StrategyZero automa.EffectiveStrategy = 100 // StrategyDefault indicates the value came from a hardcoded compile-time // constant (e.g. deps.BLOCK_NODE_NAMESPACE). Set via WithDefaults and // typically never changes after initial wiring. StrategyDefault automa.EffectiveStrategy = 101 // StrategyEnv indicates the value came from an environment variable // (e.g. SOLO_PROVISIONER_BLOCKNODE_NAMESPACE). StrategyEnv automa.EffectiveStrategy = 102 // StrategyConfig indicates the value came from the config file loaded at // startup (e.g. config.yaml). StrategyConfig automa.EffectiveStrategy = 103 // StrategyState indicates the value came from persisted application state // (state.yaml on disk). Set by WithState. StrategyState automa.EffectiveStrategy = 104 // StrategyReality indicates the value came from a live cluster query via // the reality checker. Set by RefreshState. Takes precedence over // StrategyState because it reflects the cluster's actual current condition. StrategyReality automa.EffectiveStrategy = 105 // StrategyUserInput indicates the value was supplied explicitly by the // operator via a CLI flag. Takes precedence over all configuration and // environment sources, but not over live cluster reality or persisted state. StrategyUserInput automa.EffectiveStrategy = 106 )
RSL-specific strategy constants extend automa.EffectiveStrategy using values 100–106 to avoid conflicts with automa's built-in range (0–4).
Precedence order (highest → lowest):
StrategyReality (105) > StrategyState (104) > StrategyUserInput (106) > StrategyEnv (102) > StrategyConfig (103) > StrategyDefault (101) > StrategyZero (100)
Note: numeric values do not encode precedence — the order is defined explicitly in [defaultOrderedStrategies].
const DefaultRefreshInterval = 10 * time.Minute
DefaultRefreshInterval is the default duration after which the resolver should refresh its state from the reality checker. This is a balance between ensuring reasonably fresh state and avoiding excessive calls to the reality checker, which may be expensive or rate-limited.
const DefaultRefreshTimeout = 60 * time.Second
DefaultRefreshTimeout is the default timeout for state refresh operations, which may involve calls to external systems and should not be allowed to run indefinitely.
Variables ¶
This section is empty.
Functions ¶
func StrategyName ¶ added in v0.16.0
func StrategyName(s automa.EffectiveStrategy) string
StrategyName returns the human-readable label for any automa.EffectiveStrategy value, including RSL-specific constants (100–106) that automa's own String() method does not know about. For automa built-in strategies the result matches automa's own String() output.
Types ¶
type BlockNodeRuntimeResolver ¶
type BlockNodeRuntimeResolver struct {
// contains filtered or unexported fields
}
BlockNodeRuntimeResolver manages the current state of block-node related information.
Each resolvable field owns an *EffectiveValueResolver[T] that holds all value sources in a map keyed by strategy. Resolution precedence (highest → lowest):
StrategyReality – live cluster (from RefreshState) StrategyState – persisted state on disk (from WithState) StrategyUserInput – CLI flags (from WithUserInputs) StrategyEnv – environment variables (set externally via SetSource) StrategyConfig – config file (from WithConfig) StrategyDefault – hardcoded deps.* constants (seeded at construction) StrategyZero – zero value (ultimate fallback)
func (*BlockNodeRuntimeResolver) ChartName ¶
func (b *BlockNodeRuntimeResolver) ChartName() (*EffectiveValue[string], error)
func (*BlockNodeRuntimeResolver) ChartRef ¶
func (b *BlockNodeRuntimeResolver) ChartRef() (*EffectiveValue[string], error)
func (*BlockNodeRuntimeResolver) ChartVersion ¶
func (b *BlockNodeRuntimeResolver) ChartVersion() (*EffectiveValue[string], error)
func (*BlockNodeRuntimeResolver) CurrentState ¶
func (b *BlockNodeRuntimeResolver) CurrentState() (state.BlockNodeState, error)
func (*BlockNodeRuntimeResolver) HistoricRetention ¶ added in v0.16.0
func (b *BlockNodeRuntimeResolver) HistoricRetention() (*EffectiveValue[string], error)
HistoricRetention returns the effective historic block retention threshold resolver.
func (*BlockNodeRuntimeResolver) Namespace ¶
func (b *BlockNodeRuntimeResolver) Namespace() (*EffectiveValue[string], error)
Namespace returns the effective namespace resolver. The resolver carries all source layers; call Get().Val() for the winning value or the source-specific Val methods (StateVal, UserInputVal, …) to inspect layers.
func (*BlockNodeRuntimeResolver) RecentRetention ¶ added in v0.16.0
func (b *BlockNodeRuntimeResolver) RecentRetention() (*EffectiveValue[string], error)
RecentRetention returns the effective recent block retention threshold resolver.
func (*BlockNodeRuntimeResolver) RefreshState ¶
func (b *BlockNodeRuntimeResolver) RefreshState(ctx context.Context, force bool) error
func (*BlockNodeRuntimeResolver) ReleaseName ¶
func (b *BlockNodeRuntimeResolver) ReleaseName() (*EffectiveValue[string], error)
func (*BlockNodeRuntimeResolver) Storage ¶
func (b *BlockNodeRuntimeResolver) Storage() (*EffectiveValue[models.BlockNodeStorage], error)
func (*BlockNodeRuntimeResolver) WithConfig ¶
func (b *BlockNodeRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.BlockNodeState, models.BlockNodeInputs]
func (*BlockNodeRuntimeResolver) WithDefaults ¶ added in v0.16.0
func (b *BlockNodeRuntimeResolver) WithDefaults(cfg models.Config) Resolver[state.BlockNodeState, models.BlockNodeInputs]
WithDefaults registers hardcoded compile-time constants as StrategyDefault sources — the lowest-priority fallback in the resolution chain. cfg should be the result of config.DefaultsConfig() (i.e. values sourced exclusively from the deps package).
Zero-value fields in cfg are not registered so they don't shadow a higher-priority source with an empty string.
func (*BlockNodeRuntimeResolver) WithEnv ¶ added in v0.16.0
func (b *BlockNodeRuntimeResolver) WithEnv(cfg models.Config) Resolver[state.BlockNodeState, models.BlockNodeInputs]
WithEnv registers env-var-sourced values as StrategyEnv sources, giving them the correct precedence: above StrategyConfig (config file) but below StrategyUserInput (CLI flags).
cfg should be the result of config.EnvConfig() — a models.Config populated exclusively from SOLO_PROVISIONER_* environment variables, with zero values for fields that have no matching env var. Zero values are not registered as sources so they don't shadow the config file.
func (*BlockNodeRuntimeResolver) WithIntent ¶
func (b *BlockNodeRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.BlockNodeState, models.BlockNodeInputs]
func (*BlockNodeRuntimeResolver) WithState ¶
func (b *BlockNodeRuntimeResolver) WithState(st state.BlockNodeState) Resolver[state.BlockNodeState, models.BlockNodeInputs]
func (*BlockNodeRuntimeResolver) WithUserInputs ¶
func (b *BlockNodeRuntimeResolver) WithUserInputs(inputs models.BlockNodeInputs) Resolver[state.BlockNodeState, models.BlockNodeInputs]
type ClusterRuntimeResolver ¶
type ClusterRuntimeResolver struct {
// contains filtered or unexported fields
}
func (*ClusterRuntimeResolver) CurrentState ¶
func (c *ClusterRuntimeResolver) CurrentState() (state.ClusterState, error)
func (*ClusterRuntimeResolver) RefreshState ¶
func (c *ClusterRuntimeResolver) RefreshState(ctx context.Context, force bool) error
RefreshState refreshes the current state using the configured reality checker. It respects refreshInterval by comparing against the concrete ClusterState.LastSync field rather than using an injected helper.
func (*ClusterRuntimeResolver) WithConfig ¶
func (c *ClusterRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.ClusterState, models.ClusterInputs]
func (*ClusterRuntimeResolver) WithDefaults ¶ added in v0.16.0
func (c *ClusterRuntimeResolver) WithDefaults(_ models.Config) Resolver[state.ClusterState, models.ClusterInputs]
WithDefaults is a no-op stub satisfying the Resolver interface. ClusterRuntimeResolver has no field-level EffectiveValue resolvers yet.
func (*ClusterRuntimeResolver) WithEnv ¶ added in v0.16.0
func (c *ClusterRuntimeResolver) WithEnv(_ models.Config) Resolver[state.ClusterState, models.ClusterInputs]
WithEnv is a no-op stub satisfying the Resolver interface. ClusterRuntimeResolver has no field-level EffectiveValue resolvers yet, so env var injection is not applicable.
func (*ClusterRuntimeResolver) WithIntent ¶
func (c *ClusterRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.ClusterState, models.ClusterInputs]
func (*ClusterRuntimeResolver) WithState ¶
func (c *ClusterRuntimeResolver) WithState(st state.ClusterState) Resolver[state.ClusterState, models.ClusterInputs]
func (*ClusterRuntimeResolver) WithUserInputs ¶
func (c *ClusterRuntimeResolver) WithUserInputs(inputs models.ClusterInputs) Resolver[state.ClusterState, models.ClusterInputs]
type DefaultSelector ¶ added in v0.16.0
type DefaultSelector[T any] struct{}
DefaultSelector is the standard Selector implementation. It walks [defaultOrderedStrategies] in order and returns the first source whose key exists in the map, regardless of the value. If no source is present it returns a zero value tagged with StrategyZero.
func (*DefaultSelector[T]) Resolve ¶ added in v0.16.0
func (dfr *DefaultSelector[T]) Resolve(sources map[automa.EffectiveStrategy]automa.Value[T]) (*automa.EffectiveValue[T], error)
Resolve implements Selector using the default priority-walk over [defaultOrderedStrategies].
type EffectiveValue ¶ added in v0.16.0
type EffectiveValue[T any] struct { // contains filtered or unexported fields }
EffectiveValue holds all value sources for a single configurable field together with the Selector that picks the winner.
Sources ¶
Each source is stored in a map keyed by automa.EffectiveStrategy. Sources are populated by the owner (e.g. BlockNodeRuntimeResolver) via EffectiveValue.SetSource and removed via EffectiveValue.ClearSource. Multiple sources can coexist; the Selector decides which one wins.
Lazy resolution and caching ¶
Resolution is deferred until the first call to EffectiveValue.Resolve, EffectiveValue.Get, EffectiveValue.Strategy, or EffectiveValue.Err. Both the result and any error are cached so subsequent calls are free. Any call to EffectiveValue.SetSource, EffectiveValue.ClearSource, or EffectiveValue.Invalidate clears the cache and forces recomputation on the next access.
Source inspection ¶
Callers can inspect individual source layers at any time — before or after resolution — using the typed accessors: EffectiveValue.RealityVal, EffectiveValue.StateVal, EffectiveValue.UserInputVal, EffectiveValue.EnvVal, EffectiveValue.ConfigVal, EffectiveValue.DefaultVal. These never trigger resolution and never return errors.
func NewEffectiveValue ¶ added in v0.16.0
func NewEffectiveValue[T any](selector Selector[T]) (*EffectiveValue[T], error)
NewEffectiveValue constructs an EffectiveValue for a single field with an empty sources map. Callers populate sources via EffectiveValue.SetSource or the owning resolver's With* methods (WithDefaults, WithConfig, WithEnv, …). selector is the Selector invoked on the first call to EffectiveValue.Resolve. If selector is nil, DefaultSelector is used.
func (*EffectiveValue[T]) ClearSource ¶ added in v0.16.0
func (e *EffectiveValue[T]) ClearSource(strategy automa.EffectiveStrategy)
ClearSource removes the value for the given strategy from the sources map and invalidates the cached result. It is a no-op if the strategy was not present.
func (*EffectiveValue[T]) ConfigVal ¶ added in v0.16.0
func (e *EffectiveValue[T]) ConfigVal() (automa.Value[T], error)
ConfigVal returns the value registered under StrategyConfig (the config file loaded at startup) without triggering resolution. Returns EffectiveValue.ZeroVal if no config source has been registered.
func (*EffectiveValue[T]) DefaultVal ¶ added in v0.16.0
func (e *EffectiveValue[T]) DefaultVal() (automa.Value[T], error)
DefaultVal returns the value registered under StrategyDefault (the hardcoded compile-time constant) without triggering resolution. Returns EffectiveValue.ZeroVal if no default source has been registered.
func (*EffectiveValue[T]) EnvVal ¶ added in v0.16.0
func (e *EffectiveValue[T]) EnvVal() (automa.Value[T], error)
EnvVal returns the value registered under StrategyEnv (an environment variable) without triggering resolution. Returns EffectiveValue.ZeroVal if no env source has been registered.
func (*EffectiveValue[T]) Err ¶ added in v0.16.0
func (e *EffectiveValue[T]) Err() error
Err returns the cached resolution error, triggering resolution if it has not yet been computed. Returns nil when resolution succeeded or has not been attempted yet and there is no cached error.
func (*EffectiveValue[T]) Get ¶ added in v0.16.0
func (e *EffectiveValue[T]) Get() automa.Value[T]
Get returns the winning automa.Value[T] by lazily triggering resolution. If resolution fails it returns EffectiveValue.ZeroVal so the call is always safe — it never panics.
This method is a drop-in replacement for automa.EffectiveValue.Get. Callers that need the error should use EffectiveValue.Resolve or EffectiveValue.Err instead.
func (*EffectiveValue[T]) Invalidate ¶ added in v0.16.0
func (e *EffectiveValue[T]) Invalidate()
Invalidate clears the cached result and cached error so the next call to EffectiveValue.Resolve (or any lazy accessor) recomputes from the current sources. It is called automatically by EffectiveValue.SetSource and EffectiveValue.ClearSource; call it directly only when the owning struct has mutated external state that the Selector closes over (e.g. intent change in [chartVersionResolver]).
func (*EffectiveValue[T]) MarshalJSON ¶ added in v0.16.0
func (e *EffectiveValue[T]) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler, emitting a structured JSON object so that zerolog's Any() and other JSON encoders produce a queryable log field rather than a plain text string or an empty "{}".
Output shape:
{"strategy":"<name>","value":<val>,"sources":{"<name>":<val>,…}}
"strategy" and "value" reflect the winning source. "sources" contains every registered (non-zero) source keyed by strategy name. Resolution errors are surfaced as the "value" string "<error: …>" and strategy "zero".
func (*EffectiveValue[T]) RealityVal ¶ added in v0.16.0
func (e *EffectiveValue[T]) RealityVal() (automa.Value[T], error)
RealityVal returns the value registered under StrategyReality (the live cluster query result) without triggering resolution. Returns EffectiveValue.ZeroVal if a reality refresh has not yet been performed or the release is not deployed.
func (*EffectiveValue[T]) Resolve ¶ added in v0.16.0
func (e *EffectiveValue[T]) Resolve() (*automa.EffectiveValue[T], error)
Resolve computes the effective value by invoking the Selector with the current sources map. Both the winning value and any error are cached after the first call; subsequent calls return the cached result without recomputing.
To force recomputation after mutating sources, call EffectiveValue.Invalidate or use EffectiveValue.SetSource / EffectiveValue.ClearSource, which invalidate the cache automatically.
func (*EffectiveValue[T]) SetSource ¶ added in v0.16.0
func (e *EffectiveValue[T]) SetSource(strategy automa.EffectiveStrategy, v T) error
SetSource registers v as the value for the given strategy and invalidates the cached result. If v cannot be encoded by gob (required by automa's Value internals) an error is returned and the sources map is not mutated.
func (*EffectiveValue[T]) StateVal ¶ added in v0.16.0
func (e *EffectiveValue[T]) StateVal() (automa.Value[T], error)
StateVal returns the value registered under StrategyState (persisted state.yaml) without triggering resolution. Returns EffectiveValue.ZeroVal if the field has no persisted state.
func (*EffectiveValue[T]) Strategy ¶ added in v0.16.0
func (e *EffectiveValue[T]) Strategy() automa.EffectiveStrategy
Strategy returns the automa.EffectiveStrategy of the winning source by lazily triggering resolution. Returns StrategyZero if resolution fails.
This method is a drop-in replacement for automa.EffectiveValue.Strategy. Note: because RSL strategy constants (100–106) are outside automa's known range, calling .String() on the returned value produces "unknown". Use EffectiveValue.StrategyName for a human-readable label instead.
func (*EffectiveValue[T]) StrategyName ¶ added in v0.16.0
func (e *EffectiveValue[T]) StrategyName() string
StrategyName returns the human-readable label for the winning strategy (e.g. "reality", "state", "userInput"). Unlike calling Strategy().String() directly — which returns "unknown" for RSL-specific constants — this method correctly maps the full range 100–106 via the package-level StrategyName function.
func (*EffectiveValue[T]) String ¶ added in v0.16.0
func (e *EffectiveValue[T]) String() string
String returns a human-readable one-liner summary of the effective value, intended for console output, fmt.Sprintf, and error messages. For structured logging use logx.Any() — which calls MarshalJSON().
Format:
strategy=<name> value=<val> sources=[<name>:<val>, …]
Sources are listed in precedence order (highest → lowest), skipping StrategyZero since it is the implicit fallback and never stored. Resolution is triggered lazily if not yet cached; errors are surfaced as value=<error: …>.
func (*EffectiveValue[T]) UserInputVal ¶ added in v0.16.0
func (e *EffectiveValue[T]) UserInputVal() (automa.Value[T], error)
UserInputVal returns the value registered under StrategyUserInput (a CLI flag) without triggering resolution. Returns EffectiveValue.ZeroVal if the user did not supply this field.
func (*EffectiveValue[T]) ValOf ¶ added in v0.16.0
func (e *EffectiveValue[T]) ValOf(sourceStrategy automa.EffectiveStrategy) automa.Value[T]
ValOf returns the raw automa.Value[T] registered for sourceStrategy without triggering resolution. If the strategy has no registered source it returns EffectiveValue.ZeroVal. Use the typed accessors (EffectiveValue.StateVal, EffectiveValue.UserInputVal, etc.) for self-documenting call sites.
func (*EffectiveValue[T]) WithSelector ¶ added in v0.16.0
func (e *EffectiveValue[T]) WithSelector(selector Selector[T])
WithSelector replaces the current Selector and invalidates the cache so the next call to EffectiveValue.Resolve uses the new algorithm.
func (*EffectiveValue[T]) ZeroVal ¶ added in v0.16.0
func (e *EffectiveValue[T]) ZeroVal() automa.Value[T]
ZeroVal returns the zero value of T wrapped as an automa.Value[T]. It is used as a safe fallback when no source is available or resolution fails.
type MachineRuntimeResolver ¶
type MachineRuntimeResolver struct {
// contains filtered or unexported fields
}
MachineRuntimeResolver manages the current machine state (software and hardware) for the local host. Unlike BlockNodeRuntimeResolver, it does not perform per-field EffectiveValue resolution across multiple sources (env vars, config file, user inputs, persisted state, reality). Machine state has a single authoritative source — the reality checker — so the resolver simply stores the latest snapshot returned by that checker and exposes it for direct reads.
The With* methods (WithIntent, WithUserInputs, WithConfig, WithDefaults, WithEnv) are implemented as required by the Resolver interface but are no-ops here; they exist only to satisfy the generic contract shared with BlockNodeRuntimeResolver and ClusterRuntimeResolver.
func (*MachineRuntimeResolver) CurrentState ¶
func (m *MachineRuntimeResolver) CurrentState() (state.MachineState, error)
func (*MachineRuntimeResolver) RefreshState ¶
func (m *MachineRuntimeResolver) RefreshState(ctx context.Context, force bool) error
RefreshState refreshes the current machine state from the reality checker, using the concrete MachineState.LastSync to apply refresh interval checks.
func (*MachineRuntimeResolver) SoftwareState ¶ added in v0.16.0
func (m *MachineRuntimeResolver) SoftwareState(name string) (state.SoftwareState, bool)
SoftwareState looks up the named component in the most recent machine state snapshot. Returns (zero, false) when the snapshot has not yet been synced (nil state or zero LastSync), signalling the caller to fall back to disk verification. Returns (zero, false) when the component is absent from the snapshot (unrecognised name). Returns (sw, true) when the snapshot is available and the component is present.
func (*MachineRuntimeResolver) WithConfig ¶
func (m *MachineRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.MachineState, models.MachineInputs]
func (*MachineRuntimeResolver) WithDefaults ¶ added in v0.16.0
func (m *MachineRuntimeResolver) WithDefaults(_ models.Config) Resolver[state.MachineState, models.MachineInputs]
WithDefaults is a no-op stub satisfying the Resolver interface. MachineRuntimeResolver has no field-level EffectiveValue resolvers yet.
func (*MachineRuntimeResolver) WithEnv ¶ added in v0.16.0
func (m *MachineRuntimeResolver) WithEnv(_ models.Config) Resolver[state.MachineState, models.MachineInputs]
WithEnv is a no-op stub satisfying the Resolver interface. MachineRuntimeResolver has no field-level EffectiveValue resolvers yet, so env var injection is not applicable.
func (*MachineRuntimeResolver) WithIntent ¶
func (m *MachineRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.MachineState, models.MachineInputs]
func (*MachineRuntimeResolver) WithState ¶
func (m *MachineRuntimeResolver) WithState(st state.MachineState) Resolver[state.MachineState, models.MachineInputs]
func (*MachineRuntimeResolver) WithUserInputs ¶
func (m *MachineRuntimeResolver) WithUserInputs(inputs models.MachineInputs) Resolver[state.MachineState, models.MachineInputs]
type Resolver ¶
type Resolver[S any, I any] interface { WithIntent(intent models.Intent) Resolver[S, I] WithUserInputs(inputs I) Resolver[S, I] WithDefaults(cfg models.Config) Resolver[S, I] WithConfig(cfg models.Config) Resolver[S, I] WithEnv(cfg models.Config) Resolver[S, I] WithState(blockNodeState S) Resolver[S, I] RefreshState(ctx context.Context, force bool) error CurrentState() (S, error) }
func NewBlockNodeRuntimeResolver ¶
func NewBlockNodeRuntimeResolver( cfg models.Config, blockNodeState state.BlockNodeState, realityChecker reality.Checker[state.BlockNodeState], refreshInterval time.Duration, ) (Resolver[state.BlockNodeState, models.BlockNodeInputs], error)
func NewClusterRuntimeResolver ¶
func NewClusterRuntimeResolver( cfg models.Config, clusterState state.ClusterState, realityChecker reality.Checker[state.ClusterState], refreshInterval time.Duration, ) (Resolver[state.ClusterState, models.ClusterInputs], error)
NewClusterRuntimeResolver creates a ClusterRuntime with the provided configuration, initial state, reality checker, and refresh interval. The caller is responsible for retaining and injecting the returned instance — no package-level singleton is used.
func NewMachineRuntimeResolver ¶
func NewMachineRuntimeResolver( cfg models.Config, clusterState state.MachineState, realityChecker reality.Checker[state.MachineState], refreshInterval time.Duration, ) (Resolver[state.MachineState, models.MachineInputs], error)
NewMachineRuntimeResolver creates a MachineRuntimeResolver with the provided configuration, initial state, reality checker, and refresh interval. The caller is responsible for retaining and injecting the returned instance — no package-level singleton is used.
func NewTeleportRuntimeResolver ¶ added in v0.16.0
func NewTeleportRuntimeResolver( cfg models.Config, teleportState state.TeleportState, realityChecker reality.Checker[state.TeleportState], refreshInterval time.Duration, ) (Resolver[state.TeleportState, models.TeleportNodeInputs], error)
NewTeleportRuntimeResolver creates a TeleportRuntimeResolver with per-field EffectiveValue resolvers. All fields use DefaultSelector (standard priority walk).
type RuntimeResolver ¶
type RuntimeResolver struct {
BlockNodeRuntime Resolver[state.BlockNodeState, models.BlockNodeInputs]
ClusterRuntime Resolver[state.ClusterState, models.ClusterInputs]
MachineRuntime Resolver[state.MachineState, models.MachineInputs]
TeleportRuntime Resolver[state.TeleportState, models.TeleportNodeInputs]
// contains filtered or unexported fields
}
RuntimeResolver holds the fully-initialised runtime components for all node types. It is constructed once at the composition root (main / command init) and injected into every layer that needs it, eliminating package-level singletons.
func NewRuntimeResolver ¶
func NewRuntimeResolver( cfg models.Config, sm state.Manager, realityChecker reality.Checkers, refreshInterval time.Duration, ) (*RuntimeResolver, error)
NewRuntimeResolver creates a RuntimeResolver by constructing each runtime from the supplied configuration, current persisted state, reality checker, and refresh interval.
func (*RuntimeResolver) AddActionHistory ¶
func (r *RuntimeResolver) AddActionHistory(entry state.ActionHistory) state.Writer
func (*RuntimeResolver) CurrentState ¶
func (r *RuntimeResolver) CurrentState() (state.State, error)
CurrentState reads the current state from all runtimes and composes it into a single state.State struct. This is the single source of truth for all state reads in the CLI layer, ensuring that all reads are consistent and reflect the latest reality state (subject to each runtime's staleness checks). Ensure to call Refresh() before this to ensure that all runtimes have the latest reality state
func (*RuntimeResolver) FlushAll ¶
func (r *RuntimeResolver) FlushAll(currentState state.State) error
type Selector ¶ added in v0.16.0
type Selector[T any] interface { Resolve(sources map[automa.EffectiveStrategy]automa.Value[T]) (*automa.EffectiveValue[T], error) }
Selector is the algorithm that picks the winning value from a sources map.
Implementations receive the full sources map — keyed by strategy — and return the winning automa.EffectiveValue together with any error. An error signals that resolution is impossible given the current sources (e.g. a required field is empty in a deployed release).
Use DefaultSelector for the standard priority-walk behaviour. Implement this interface directly when a field requires domain-specific rules such as:
- Validating that a deployed value is non-empty (e.g. namespace).
- Soft fall-through on an empty deployed value with a warning (e.g. chart ref).
- Intent-aware ordering where upgrade and non-upgrade actions resolve differently (e.g. chart version).
- Post-resolution merging of values from multiple sources (e.g. storage BasePath merge from config into deployed state).
type TeleportRuntimeResolver ¶ added in v0.16.0
type TeleportRuntimeResolver struct {
// contains filtered or unexported fields
}
TeleportRuntimeResolver manages the teleport state lifecycle and provides per-field effective value resolution for teleport configuration.
It uses TeleportNodeInputs as the generic input type for the Resolver interface. Cluster inputs are handled via the concrete WithClusterInputs method — callers must type-assert to *TeleportRuntimeResolver (consistent with how blocknode handlers type-assert to *BlockNodeRuntimeResolver).
func (*TeleportRuntimeResolver) CurrentState ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) CurrentState() (state.TeleportState, error)
func (*TeleportRuntimeResolver) Namespace ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) Namespace() (*EffectiveValue[string], error)
Namespace returns the effective namespace resolver for the cluster agent.
func (*TeleportRuntimeResolver) ProxyAddr ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) ProxyAddr() (*EffectiveValue[string], error)
ProxyAddr returns the effective proxy address resolver.
func (*TeleportRuntimeResolver) RefreshState ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) RefreshState(ctx context.Context, force bool) error
func (*TeleportRuntimeResolver) ReleaseName ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) ReleaseName() (*EffectiveValue[string], error)
ReleaseName returns the effective release name resolver for the cluster agent.
func (*TeleportRuntimeResolver) Token ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) Token() (*EffectiveValue[string], error)
Token returns the effective token resolver.
func (*TeleportRuntimeResolver) ValuesFile ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) ValuesFile() (*EffectiveValue[string], error)
ValuesFile returns the effective Helm values file resolver for the cluster agent.
func (*TeleportRuntimeResolver) Version ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) Version() (*EffectiveValue[string], error)
Version returns the effective chart version resolver for the cluster agent.
func (*TeleportRuntimeResolver) WithClusterInputs ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) WithClusterInputs(inputs models.TeleportClusterInputs) *TeleportRuntimeResolver
WithClusterInputs registers cluster agent user inputs as StrategyUserInput sources. This method lives on the concrete struct because the Resolver[S, I] interface is typed with TeleportNodeInputs — cluster handlers must type-assert to access it.
func (*TeleportRuntimeResolver) WithConfig ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) WithConfig(cfg models.Config) Resolver[state.TeleportState, models.TeleportNodeInputs]
func (*TeleportRuntimeResolver) WithDefaults ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) WithDefaults(cfg models.Config) Resolver[state.TeleportState, models.TeleportNodeInputs]
WithDefaults registers hardcoded compile-time constants as StrategyDefault sources. cfg should be the result of config.DefaultsConfig().
func (*TeleportRuntimeResolver) WithEnv ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) WithEnv(cfg models.Config) Resolver[state.TeleportState, models.TeleportNodeInputs]
WithEnv registers env-var-sourced values as StrategyEnv sources. cfg should be the result of config.EnvConfig().
func (*TeleportRuntimeResolver) WithIntent ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) WithIntent(intent models.Intent) Resolver[state.TeleportState, models.TeleportNodeInputs]
func (*TeleportRuntimeResolver) WithState ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) WithState(st state.TeleportState) Resolver[state.TeleportState, models.TeleportNodeInputs]
func (*TeleportRuntimeResolver) WithUserInputs ¶ added in v0.16.0
func (t *TeleportRuntimeResolver) WithUserInputs(inputs models.TeleportNodeInputs) Resolver[state.TeleportState, models.TeleportNodeInputs]