pub struct RequiredSpec {
pub regions: Vec<String>,
pub zones: Vec<String>,
pub providers: Vec<String>,
pub mesh_tags: Vec<String>,
pub nodes: Vec<String>,
pub memory_mb: u32,
pub cpu_millis: u32,
pub repel_archetype: Option<LifecycleArchetype>,
pub requires_taint: Option<String>,
}Expand description
F16 placement constraints declared on a MirrorProviderSlot, lives under
[providers.<role>] required = { regions = [...], mesh_tags = [...] } in
mirrors/<env>.toml.
Hard (must-satisfy) axes, all AND-ed together:
regions/zones/providers— membership: the machine’sregion/zone/providermust be one of the listed values.mesh_tags— superset: the machine’smesh_tagsmust contain every listed tag.memory_mb/cpu_millis— capacity floor (R572-F5): the machine’sallocatablebudget must cover the demand.0= no constraint.repel_archetype— taint repulsion (R572-F5): the machine must not carry the taint"no-<archetype.taint_key()>"for the workload’s class.None= no repulsion check. Absolute — seeSelf::repel_archetype.requires_taint— taint affinity (R572-F5): the machine must carry this taint key (intaintsormesh_tags).None= no affinity.
These two are the only readers of MachineConfig::taints, which is
what makes taint_effect’s closed vocabulary well-founded.
MachineConfig::sovereign_group is deliberately not an axis here and
must not become one (W305/R742-F1). A sovereign group is a blast radius,
not a filter: which quorum a box votes in says nothing about whether a
workload may run on it, and a dev-group node exists precisely so dev-mode
services — stateful ones included — can be scheduled onto it. Filtering on
it would re-make the mistake W305 exists to undo, where one mechanism
silently carried three unrelated properties.
An empty / zero / None on every axis means “no constraint on that axis”.
A fully-unconstrained RequiredSpec matches every machine (see
RequiredSpec::is_unconstrained).
Fields§
§regions: Vec<String>§zones: Vec<String>§providers: Vec<String>§nodes: Vec<String>R833-F8: imperative placement — the machine must be one of these by
name. Empty (the default) = no constraint, which is every pre-R833-F8
caller.
This is the one axis that is not a capability the scheduler infers.
The operator typed --where=node:us-west-003, so it composes with the
other axes exactly like the rest — a named node that fails the capacity
floor or carries a repelling taint still does not match, and the refusal
names why rather than silently placing the work somewhere else.
memory_mb: u32R572-F5: minimum memory (MiB) the target node must have in its
declared allocatable budget. 0 = no constraint. Filled by
CloudConfig::admit_workload from the workload’s
memory_request_mb() — its placement request, which is not the
same number as the resources.memory_mb cgroup ceiling.
cpu_millis: u32R572-F5: minimum CPU (millicores) the target node must have in its
declared allocatable budget. 0 = no constraint. Filled by
CloudConfig::admit_workload from the workload’s resources.cpu_millis.
repel_archetype: Option<LifecycleArchetype>R572-F5: effective archetype of the workload being placed. The scheduler
rejects any node that carries the taint "no-<archetype.taint_key()>".
None = no repulsion check (backwards-compat for callers that don’t
thread a spec through).
This is an absolute block, not a preference.
CloudConfig::admit_workload sets it unconditionally from the
workload’s effective archetype, and nothing in the tree tolerates a
taint — so a workload cannot opt out of a no-<archetype> node
(W305 finding 2 / R742-T4). Adding toleration means giving
WorkloadSpec a tolerations list and consulting it here; until then,
do not describe this as “repel-unless-tolerate”.
requires_taint: Option<String>R572-F5: taint the workload requires the target node to carry
(annotation yah.placement.requires-taint). The node must have the
key in its taints list or mesh_tags. None = no affinity constraint.
Implementations§
Source§impl RequiredSpec
impl RequiredSpec
Sourcepub fn is_unconstrained(&self) -> bool
pub fn is_unconstrained(&self) -> bool
True when no axis carries a constraint — every machine matches.
Sourcepub fn matches(&self, machine: &MachineConfig) -> bool
pub fn matches(&self, machine: &MachineConfig) -> bool
Whether machine satisfies every hard axis.
- Membership axes (region/zone/provider): machine must carry the field and it must appear in the constraint list.
mesh_tags: machine tags must be a superset of the required set.- R572-F5 capacity floor:
machine.allocatable.{memory,cpu}must coverself.{memory,cpu}. A machine with noallocatableblock passes unconditionally (capacity unknown → no constraint enforced). - R572-F5 taint repulsion: machine must not carry the taint
"no-<archetype.taint_key()>"for the workload’s class. Absolute — the workload has no way to tolerate it (W305 finding 2). - R572-F5 taint affinity: if
requires_taintis set, the machine must carry that key in itstaintslist ormesh_tags.
Any other taint on the machine is ignored here, which is precisely
why crate::validate::check_inert_taints refuses to let one be
declared: it would read as a constraint and be none.
Trait Implementations§
Source§impl Clone for RequiredSpec
impl Clone for RequiredSpec
Source§fn clone(&self) -> RequiredSpec
fn clone(&self) -> RequiredSpec
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 RequiredSpec
impl Debug for RequiredSpec
Source§impl Default for RequiredSpec
impl Default for RequiredSpec
Source§fn default() -> RequiredSpec
fn default() -> RequiredSpec
Source§impl<'de> Deserialize<'de> for RequiredSpec
impl<'de> Deserialize<'de> for RequiredSpec
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>,
Auto Trait Implementations§
impl Freeze for RequiredSpec
impl RefUnwindSafe for RequiredSpec
impl Send for RequiredSpec
impl Sync for RequiredSpec
impl Unpin for RequiredSpec
impl UnsafeUnpin for RequiredSpec
impl UnwindSafe for RequiredSpec
Blanket Implementations§
impl<T> Allocation for T
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<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<T> ErasedDestructor for Twhere
T: 'static,
impl<T> Fruit for T
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
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 more