pub struct RoutingHostname {
pub app: String,
pub instance: Option<String>,
pub cluster: Option<String>,
}Expand description
One entry in RoutingSpec.hostnames.
Emitted FQDN: ${app}.${ephemeral_id}.${cluster}.${location}.${domain}
where:
appand (optional)instancecome from this struct;clusterfalls back to reconciler-config when unset;locationanddomainare reconciler-config (fromnix/lib/fleet-domains.nix).
Fields§
§app: StringApplication slot — api, gateway, web, etc.
Must be a valid DNS label (RFC 1123): lowercase alpha-num
- hyphen, 1–63 chars, no leading/trailing hyphen. The reconciler validates this at the boundary.
instance: Option<String>Named instance segment. When Some("demo-prod") the FQDN
reads ${app}.demo-prod.${cluster}.…. When None the
reconciler substitutes blake3(canonical_spec)[:8] —
deterministic per-spec, changes when the spec changes.
Must be a valid DNS label when set.
cluster: Option<String>Cluster override. Empty/None ⇒ reconciler-config default
(e.g., pleme-dev). Used for cross-cluster routing rules,
rare in practice.
Implementations§
Source§impl RoutingHostname
impl RoutingHostname
Sourcepub fn cluster_or<'a>(&'a self, fallback: &'a str) -> &'a str
pub fn cluster_or<'a>(&'a self, fallback: &'a str) -> &'a str
Cluster override slice with a caller-supplied per-config
fallback applied — the ONE-line collapse of the paired
self.cluster.as_deref().unwrap_or(fallback) incantation the
reconciler’s FQDN composer + stable-claim group-key composer
both spelled by hand pre-lift.
Pre-lift the projection was hand-authored at TWO sites past
the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold in
tatara-reconciler, each walking the SAME borrow-form
Option<String> slot × per-config-fallback shape:
render::render_routing— per-instance FQDN composer seed forcrate::hostname::fmt_fqdn, keyed on the cluster segment.table_controller::stable_name_group_key— claim-arbiter(cluster, app)group-key seed, keyed on the cluster segment.
Both sites walked the SAME projection: pull the borrow-form
.cluster.as_deref() slot, sink an absent slot to the
per-config fallback the caller threads in from
Context.config.cluster. Post-lift both consumers read
hostname.cluster_or(cfg_cluster) — the projection sits at
ONE substrate owner, so a future normalization (a case-fold
pass, an empty-string-to-fallback promotion, a cross-cluster
alias resolver, a per-fleet cluster-name canonicalization)
lands here exactly once and every consumer (FQDN composer,
claim-arbiter group key, and any future edge whose downstream
keys on the cluster segment) inherits the upgrade
mechanically.
Peer to Self::is_named on the (OptionRoutingHostname
and hide the missing-slot corner behind ONE substrate
primitive; both preserve the borrow-form return, so downstream
composers thread the slice without a .to_string() step.
Semantics: an explicit Some("") returns the empty string
(matching the pre-lift .as_deref().unwrap_or(fallback)
chain’s behavior). Callers whose downstream rejects an
empty cluster segment must gate on that separately —
crate::hostname::fmt_fqdn’s validator does so
automatically via [crate::hostname::HostnameError:: InvalidLabel].
Sourcepub fn instanced(app: impl Into<String>, instance: impl Into<String>) -> Self
pub fn instanced(app: impl Into<String>, instance: impl Into<String>) -> Self
Compose a RoutingHostname pinned to the “named-slot,
per-config cluster fallback” shape (instance: Some(<instance>),
cluster: None) — the ONE substrate primitive owning the
3-slot RoutingHostname { app, instance: Some(<instance>), cluster: None } fixture literal every consumer restated by
hand pre-lift.
Pre-lift the same 3-slot chain (app: <s>.into(), instance: Some(<s>.into()), cluster: None) was hand-authored at TEN
workspace-wide sites past the ★★ PRIME-DIRECTIVE ≥ 2
duplication threshold, EVERY one of them the “named instance
segment, cluster-inherits-from-config” shape:
tatara-process::hostname— two sites: theresolve_named_slot_winsfixture plus theend_to_end_named_and_unnamed_for_same_processnamed-arm fixture.tatara-process::routing— four sites: thedemo_routingseed (two hostnames), thehostname_is_named_when_instance_nonemptypopulated-instance pin, and thecluster_or_borrow_form_return_shape_matches_fmt_fqdn_arg_shapeFQDN-composer parity pin.tatara-reconciler::edges— two sites: theapi_hostnametest fixture plus therouting_edge_labels_stamps_app_slot_from_hostnameAPP-slot pin (which stamps"gateway"instead of"api").tatara-reconciler::render— two sites: thetwo_hostname_routingseed’sapi+gatewayhostname pair.
Post-lift every callsite reads RoutingHostname::instanced(<app>, <instance>) and the three-slot struct’s cluster slot stays
owned by the ONE substrate site — the per-config-cluster
fallback resolved through Self::cluster_or at read time
stays the ONLY axis a cluster override travels through, so a
future normalization (a per-cluster canonicalization, a
cross-cluster alias resolver, a claim-arbiter fallback swap)
lands here exactly once and every consumer inherits the
upgrade mechanically. The impl Into<String> bound on both
positional args accepts every pre-lift caller shape verbatim
— &'static str literals, owned String values, and
.into()-terminated chains alike — without a per-site
coercion.
Peer to Self::content_hashed on the (instance slot ×
cluster slot) axis pair: both live on RoutingHostname and
hide the pair’s “per-config cluster fallback” corner behind
ONE substrate primitive; Self::instanced fills the
Some(<name>) arm of the instance slot, Self::content_hashed
fills the None arm.
Theory anchor: THEORY.md §VI.1 (generation over composition —
the RoutingHostname { app, instance: Some(<i>), cluster: None }
fixture literal recurred at ten hand-authored sites past the
★★ PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to
ONE owner here). THEORY.md §II.1 invariant 5 (composition
preserves proofs — a regression that drifted the default-
cluster sentinel from None to a hardcoded string, or
reordered the three struct slots, surfaces at the
instanced_composes_byte_identical_to_pre_lift_literal_across_every_app_instance_pair
pin below rather than as silent skew at every downstream
fixture).
Sourcepub fn content_hashed(app: impl Into<String>) -> Self
pub fn content_hashed(app: impl Into<String>) -> Self
Compose a RoutingHostname pinned to the “content-hash
anonymous, per-config cluster fallback” shape (instance: None,
cluster: None) — the ONE substrate primitive owning the
3-slot RoutingHostname { app, instance: None, cluster: None }
fixture literal every consumer restated by hand pre-lift.
The instance: None slot instructs the reconciler’s
crate::hostname::resolve_ephemeral_id to substitute
blake3(canonical_spec)[:8] — the content-hashed FQDN form
documented on RoutingHostname. Pre-lift the same 3-slot
chain (app: <s>.into(), instance: None, cluster: None)
was hand-authored at NINE workspace-wide sites past the ★★
PRIME-DIRECTIVE ≥ 2 duplication threshold, EVERY one of them
the “unnamed instance, cluster-inherits-from-config” shape:
tatara-process::hostname— two sites: theresolve_unset_named_falls_backfixture plus theend_to_end_named_and_unnamed_for_same_processanon-arm fixture.tatara-process::routing— six sites: theh_anonpin, thecluster_or_falls_back_to_caller_string_when_cluster_is_nonefallback pin, and four morecluster_or/ round-trip fixtures.tatara-reconciler::render— one site: theanonymous_hostname_uses_content_hashFQDN composer pin.
Peer to Self::instanced on the (instance slot × cluster
slot) axis pair — Self::content_hashed fills the None
arm of the instance slot, Self::instanced fills the
Some(<name>) arm.
Theory anchor: THEORY.md §VI.1 (generation over composition —
the RoutingHostname { app, instance: None, cluster: None }
fixture literal recurred at nine hand-authored sites past the
★★ PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to
ONE owner here). THEORY.md §II.1 invariant 5.
Trait Implementations§
Source§impl Clone for RoutingHostname
impl Clone for RoutingHostname
Source§fn clone(&self) -> RoutingHostname
fn clone(&self) -> RoutingHostname
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for RoutingHostname
impl Debug for RoutingHostname
Source§impl<'de> Deserialize<'de> for RoutingHostname
impl<'de> Deserialize<'de> for RoutingHostname
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for RoutingHostname
Source§impl JsonSchema for RoutingHostname
impl JsonSchema for RoutingHostname
Source§fn schema_name() -> String
fn schema_name() -> String
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn is_referenceable() -> bool
fn is_referenceable() -> bool
$ref keyword. Read moreSource§impl PartialEq for RoutingHostname
impl PartialEq for RoutingHostname
Source§impl Serialize for RoutingHostname
impl Serialize for RoutingHostname
impl StructuralPartialEq for RoutingHostname
Auto Trait Implementations§
impl Freeze for RoutingHostname
impl RefUnwindSafe for RoutingHostname
impl Send for RoutingHostname
impl Sync for RoutingHostname
impl Unpin for RoutingHostname
impl UnsafeUnpin for RoutingHostname
impl UnwindSafe for RoutingHostname
Blanket Implementations§
impl<T> AppData for Twhere
T: OptionalSend + OptionalSync + 'static + OptionalSerde,
impl<T> AppDataResponse for Twhere
T: OptionalSend + OptionalSync + 'static + OptionalSerde,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> OptionalSend for T
impl<T> OptionalSync for T
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);