mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-12-27 08:19:27 -05:00
[skip ci] template work
This commit is contained in:
parent
29f1e2da11
commit
65629f03e9
@ -217,6 +217,45 @@ fn validate_machine(machine: &Machine, _context: &ValidateContext) -> Result<(),
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum MachineLocation {
|
||||||
|
Network {
|
||||||
|
network: String,
|
||||||
|
#[serde(default)]
|
||||||
|
address4: Option<Ipv4Addr>,
|
||||||
|
#[serde(default)]
|
||||||
|
address6: Option<Ipv6Addr>,
|
||||||
|
},
|
||||||
|
Blueprint {
|
||||||
|
blueprint: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_machine_location(
|
||||||
|
value: &MachineLocation,
|
||||||
|
context: &ValidateContext,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
|
match value {
|
||||||
|
MachineLocation::Network {
|
||||||
|
network,
|
||||||
|
address4,
|
||||||
|
address6,
|
||||||
|
} => {
|
||||||
|
if address4.is_none() && address6.is_none() {
|
||||||
|
return Err(ValidationError::new("badaddr")
|
||||||
|
.with_message("machine must have at least one address".into()));
|
||||||
|
}
|
||||||
|
validate_network_exists(network, context)?;
|
||||||
|
}
|
||||||
|
MachineLocation::Blueprint { blueprint } => {
|
||||||
|
validate_blueprint_exists(blueprint, context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
||||||
#[validate(
|
#[validate(
|
||||||
context = "ValidateContext<'v_a>",
|
context = "ValidateContext<'v_a>",
|
||||||
@ -247,15 +286,28 @@ fn validate_template(
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
||||||
#[validate(schema(function = "validate_template_limits"))]
|
#[validate(schema(function = "validate_template_limits"))]
|
||||||
pub struct TemplateLimits {
|
pub struct TemplateLimits {
|
||||||
|
/// maximum number of machines this template will generate
|
||||||
#[validate(nested)]
|
#[validate(nested)]
|
||||||
pub machine_count: WeightedList<u32>,
|
#[serde(default)]
|
||||||
|
pub machine_count: Option<WeightedList<u32>>,
|
||||||
|
#[validate(nested)]
|
||||||
|
pub machines_per_network: WeightedList<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_template_limits(limits: &TemplateLimits) -> Result<(), ValidationError> {
|
fn validate_template_limits(limits: &TemplateLimits) -> Result<(), ValidationError> {
|
||||||
limits.machine_count.try_for_each(|x| {
|
if let Some(machine_count) = &limits.machine_count {
|
||||||
|
machine_count.try_for_each(|x| {
|
||||||
|
if *x == 0 {
|
||||||
|
return Err(ValidationError::new("badcount")
|
||||||
|
.with_message("template limits has zero machine count".into()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
limits.machines_per_network.try_for_each(|x| {
|
||||||
if *x == 0 {
|
if *x == 0 {
|
||||||
return Err(ValidationError::new("badcount")
|
return Err(ValidationError::new("badcount")
|
||||||
.with_message("template limits has zero machine count".into()));
|
.with_message("template limits has zero machines per network count".into()));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
@ -263,39 +315,6 @@ fn validate_template_limits(limits: &TemplateLimits) -> Result<(), ValidationErr
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum MachineLocation {
|
|
||||||
Specific {
|
|
||||||
network: String,
|
|
||||||
#[serde(default)]
|
|
||||||
address4: Option<Ipv4Addr>,
|
|
||||||
#[serde(default)]
|
|
||||||
address6: Option<Ipv6Addr>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_machine_location(
|
|
||||||
value: &MachineLocation,
|
|
||||||
context: &ValidateContext,
|
|
||||||
) -> Result<(), ValidationError> {
|
|
||||||
match value {
|
|
||||||
MachineLocation::Specific {
|
|
||||||
network,
|
|
||||||
address4,
|
|
||||||
address6,
|
|
||||||
} => {
|
|
||||||
if address4.is_none() && address6.is_none() {
|
|
||||||
return Err(ValidationError::new("badaddr")
|
|
||||||
.with_message("machine must have at least one address".into()));
|
|
||||||
}
|
|
||||||
validate_network_exists(network, context)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum TemplateLocation {
|
pub enum TemplateLocation {
|
||||||
@ -433,18 +452,22 @@ fn validate_blueprint(
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
||||||
#[validate(schema(function = "validate_blueprint_limits"))]
|
#[validate(schema(function = "validate_blueprint_limits"))]
|
||||||
pub struct BlueprintLimits {
|
pub struct BlueprintLimits {
|
||||||
|
/// maximum number of networks this blueprint will generate
|
||||||
#[validate(nested)]
|
#[validate(nested)]
|
||||||
pub network_count: WeightedList<u32>,
|
#[serde(default)]
|
||||||
|
pub network_count: Option<WeightedList<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_blueprint_limits(limits: &BlueprintLimits) -> Result<(), ValidationError> {
|
fn validate_blueprint_limits(limits: &BlueprintLimits) -> Result<(), ValidationError> {
|
||||||
limits.network_count.try_for_each(|x| {
|
if let Some(network_count) = &limits.network_count {
|
||||||
if *x == 0 {
|
network_count.try_for_each(|x| {
|
||||||
return Err(ValidationError::new("badcount")
|
if *x == 0 {
|
||||||
.with_message("blueprint limits has zero machine count".into()));
|
return Err(ValidationError::new("badcount")
|
||||||
}
|
.with_message("blueprint limits has zero network count".into()));
|
||||||
Ok(())
|
}
|
||||||
})?;
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,11 @@ machines:
|
|||||||
#################################################################
|
#################################################################
|
||||||
# Templates
|
# Templates
|
||||||
#
|
#
|
||||||
# Templates are used to generate Machines that are all on a single
|
# Templates are used to generate Machines
|
||||||
# network. A maximum number of machines are allocated on the
|
# * if networks are specified, then all machines are created on that
|
||||||
# network within the limits specified.
|
# single network. A maximum number of machines are allocated on the
|
||||||
|
# network within the limits specified.
|
||||||
|
# * if a blueprint is spec
|
||||||
|
|
||||||
templates:
|
templates:
|
||||||
# Default servers on the boot network
|
# Default servers on the boot network
|
||||||
@ -77,22 +79,23 @@ templates:
|
|||||||
bootrelay:
|
bootrelay:
|
||||||
network: "boot"
|
network: "boot"
|
||||||
machine_count: 4
|
machine_count: 4
|
||||||
|
machines_per_network: 4
|
||||||
# Servers on subnets within the 'internet' network
|
# Servers on subnets within the 'internet' network
|
||||||
relayserver:
|
relayserver:
|
||||||
blueprint: "direct"
|
blueprint: "direct"
|
||||||
machine_count: [1, 2, 3]
|
machines_per_network: [1, 2, 3]
|
||||||
ipv4server:
|
ipv4server:
|
||||||
blueprint: "direct_ipv4_no_ipv6"
|
blueprint: "direct_ipv4_no_ipv6"
|
||||||
machine_count: [1, 2, 3]
|
machines_per_network: [1, 2, 3]
|
||||||
ipv6server:
|
ipv6server:
|
||||||
blueprint: "direct_ipv6_no_ipv4"
|
blueprint: "direct_ipv6_no_ipv4"
|
||||||
machine_count: [1, 2, 3]
|
machines_per_network: [1, 2, 3]
|
||||||
nat4home:
|
nat4home:
|
||||||
blueprint: "nat_ipv4_no_ipv6"
|
blueprint: "nat_ipv4_no_ipv6"
|
||||||
machine_count: [1, 2, 3]
|
machines_per_network: [1, 2, 3]
|
||||||
nat4+6home:
|
nat4+6home:
|
||||||
blueprint: "nat_ipv4_direct_ipv6"
|
blueprint: "nat_ipv4_direct_ipv6"
|
||||||
machine_count: [1, 2, 3]
|
machines_per_network: [1, 2, 3]
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
# Networks
|
# Networks
|
||||||
|
@ -264,51 +264,14 @@ impl MachineRegistryInner {
|
|||||||
let machine_def = {
|
let machine_def = {
|
||||||
// Get the active template state
|
// Get the active template state
|
||||||
let template_state = self.get_or_create_template_state(&name, template_def)?;
|
let template_state = self.get_or_create_template_state(&name, template_def)?;
|
||||||
if !template_state.is_active()? {
|
if !template_state.is_active(self)? {
|
||||||
return Err(MachineRegistryError::TemplateComplete);
|
return Err(MachineRegistryError::TemplateComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick or instantiate an available network
|
// Pick or instantiate an available network
|
||||||
xxx add 'def()' selector to all types
|
template_state.instantiate(self)?
|
||||||
let active_networks = match template_state.template_def.location.clone() {
|
|
||||||
config::TemplateLocation::Network { network } => {
|
|
||||||
// Filter the weighted list of networks to those that are still active or not yet started and can allocate
|
|
||||||
let Some(active_networks) = network.try_filter(|n| {
|
|
||||||
self.get_network_state_by_name(&n)
|
|
||||||
.map(|ns| ns.is_active())
|
|
||||||
.unwrap_or(Ok(true))
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Err(MachineRegistryError::NetworkComplete);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
config::TemplateLocation::Blueprint { blueprint } => {
|
|
||||||
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
|
||||||
let Some(active_blueprints) = blueprint.try_filter(|b| {
|
|
||||||
self.get_blueprint_state(&b)
|
|
||||||
.map(|bs| bs.is_active(self))
|
|
||||||
.unwrap_or(Ok(true))
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Err(MachineRegistryError::BlueprintComplete);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Activate some blueprint and pick a network
|
xxx how to pass through per-network limits
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Weighted choice of network now that we have a candidate list
|
|
||||||
//let network =
|
|
||||||
|
|
||||||
config::Machine {
|
|
||||||
location: config::MachineLocation::Specific {
|
|
||||||
network: todo!(),
|
|
||||||
address4: None,
|
|
||||||
address6: None,
|
|
||||||
},
|
|
||||||
disable_capabilities: template_state.template_def.disable_capabilities.clone(),
|
|
||||||
bootstrap: false,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate a machine id
|
// Allocate a machine id
|
||||||
@ -321,9 +284,9 @@ impl MachineRegistryInner {
|
|||||||
// Create a new machine state
|
// Create a new machine state
|
||||||
let machine_state = match MachineState::try_new(
|
let machine_state = match MachineState::try_new(
|
||||||
self,
|
self,
|
||||||
|
machine_id,
|
||||||
MachineStateName::Template(name.clone()),
|
MachineStateName::Template(name.clone()),
|
||||||
machine_def.clone(),
|
machine_def.clone(),
|
||||||
machine_id,
|
|
||||||
) {
|
) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -345,12 +308,10 @@ impl MachineRegistryInner {
|
|||||||
// Return the unique id
|
// Return the unique id
|
||||||
Ok(machine_id)
|
Ok(machine_id)
|
||||||
}
|
}
|
||||||
pub(super) fn get_template_state(
|
pub(super) fn get_template_state(&self, name: &String) -> MachineRegistryResult<TemplateState> {
|
||||||
&mut self,
|
|
||||||
name: &String,
|
|
||||||
) -> MachineRegistryResult<&mut TemplateState> {
|
|
||||||
self.template_state_by_name
|
self.template_state_by_name
|
||||||
.get_mut(name)
|
.get(name)
|
||||||
|
.cloned()
|
||||||
.ok_or_else(|| MachineRegistryError::TemplateNotFound)
|
.ok_or_else(|| MachineRegistryError::TemplateNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +320,7 @@ impl MachineRegistryInner {
|
|||||||
machine_location: &config::MachineLocation,
|
machine_location: &config::MachineLocation,
|
||||||
) -> MachineRegistryResult<NetworkState> {
|
) -> MachineRegistryResult<NetworkState> {
|
||||||
match machine_location {
|
match machine_location {
|
||||||
config::MachineLocation::Specific {
|
config::MachineLocation::Network {
|
||||||
network: name,
|
network: name,
|
||||||
address4: _,
|
address4: _,
|
||||||
address6: _,
|
address6: _,
|
||||||
@ -373,6 +334,17 @@ impl MachineRegistryInner {
|
|||||||
.expect("config validation is broken");
|
.expect("config validation is broken");
|
||||||
self.get_or_create_network_state(name.clone(), network_def)
|
self.get_or_create_network_state(name.clone(), network_def)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config::MachineLocation::Blueprint { blueprint: name } => {
|
||||||
|
let blueprint_def = self
|
||||||
|
.unlocked_inner
|
||||||
|
.config
|
||||||
|
.blueprints
|
||||||
|
.get(name)
|
||||||
|
.cloned()
|
||||||
|
.expect("config validation is broken");
|
||||||
|
self.get_or_create_network_state_from_blueprint(name.clone(), blueprint_def)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(super) fn get_or_create_network_state_from_template_location(
|
pub(super) fn get_or_create_network_state_from_template_location(
|
||||||
@ -406,11 +378,12 @@ impl MachineRegistryInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_blueprint_state(
|
pub(super) fn get_blueprint_state(
|
||||||
&mut self,
|
&self,
|
||||||
name: &String,
|
name: &String,
|
||||||
) -> MachineRegistryResult<&mut BlueprintState> {
|
) -> MachineRegistryResult<BlueprintState> {
|
||||||
self.blueprint_state_by_name
|
self.blueprint_state_by_name
|
||||||
.get_mut(name)
|
.get(name)
|
||||||
|
.cloned()
|
||||||
.ok_or_else(|| MachineRegistryError::BlueprintNotFound)
|
.ok_or_else(|| MachineRegistryError::BlueprintNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,26 +506,18 @@ impl MachineRegistryInner {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: String,
|
name: String,
|
||||||
blueprint_def: config::Blueprint,
|
blueprint_def: config::Blueprint,
|
||||||
) -> MachineRegistryResult<NetworkId> {
|
) -> MachineRegistryResult<NetworkState> {
|
||||||
// Get the active blueprint state
|
// Get the active blueprint state
|
||||||
let blueprint_state = self.get_or_create_blueprint_state(&name, blueprint_def)?;
|
let blueprint_state = self.get_or_create_blueprint_state(&name, blueprint_def)?;
|
||||||
if !blueprint_state.is_active(self)? {
|
if !blueprint_state.is_active(self)? {
|
||||||
return Err(MachineRegistryError::BlueprintComplete);
|
return Err(MachineRegistryError::BlueprintComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
//xxx
|
// Make network def from current blueprint state
|
||||||
// Make machine def from current template state
|
let machine_def = config::Network {
|
||||||
let machine_def = config::Machine {
|
model: self.unlocked_inner.srng.weighted_choice(blueprint_state),
|
||||||
location: match template_state.template_def.location.clone() {
|
ipv4: todo!(),
|
||||||
config::TemplateLocation::Network { network } => {
|
ipv6: todo!(),
|
||||||
config::MachineLocation::Network { network }
|
|
||||||
}
|
|
||||||
config::TemplateLocation::Blueprint { blueprint } => {
|
|
||||||
config::MachineLocation::Blueprint { blueprint }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disable_capabilities: template_state.template_def.disable_capabilities.clone(),
|
|
||||||
bootstrap: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate a machine id
|
// Allocate a machine id
|
||||||
|
@ -8,7 +8,7 @@ struct BlueprintStateUnlockedInner {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct BlueprintStateInner {
|
struct BlueprintStateInner {
|
||||||
limit_network_count: u32,
|
limit_network_count: Option<u32>,
|
||||||
networks: HashSet<NetworkId>,
|
networks: HashSet<NetworkId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,10 +24,12 @@ impl BlueprintState {
|
|||||||
name: String,
|
name: String,
|
||||||
blueprint_def: config::Blueprint,
|
blueprint_def: config::Blueprint,
|
||||||
) -> MachineRegistryResult<BlueprintState> {
|
) -> MachineRegistryResult<BlueprintState> {
|
||||||
let limit_network_count = *machine_registry_inner
|
let limit_network_count = blueprint_def.limits.network_count.as_ref().map(|nc| {
|
||||||
.unlocked_inner
|
*machine_registry_inner
|
||||||
.srng
|
.unlocked_inner
|
||||||
.weighted_choice(&blueprint_def.limits.network_count);
|
.srng
|
||||||
|
.weighted_choice(nc)
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
unlocked_inner: Arc::new(BlueprintStateUnlockedInner {
|
unlocked_inner: Arc::new(BlueprintStateUnlockedInner {
|
||||||
@ -41,6 +43,10 @@ impl BlueprintState {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn def(&self) -> &config::Blueprint {
|
||||||
|
&self.unlocked_inner.blueprint_def
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_active(
|
pub fn is_active(
|
||||||
&self,
|
&self,
|
||||||
machine_registry_inner: &MachineRegistryInner,
|
machine_registry_inner: &MachineRegistryInner,
|
||||||
|
@ -60,7 +60,7 @@ impl MachineState {
|
|||||||
// Make the default route interface
|
// Make the default route interface
|
||||||
let machine_location = machine_def.location.clone();
|
let machine_location = machine_def.location.clone();
|
||||||
let (allocate_v4, opt_address4, allocate_v6, opt_address6) = match machine_location {
|
let (allocate_v4, opt_address4, allocate_v6, opt_address6) = match machine_location {
|
||||||
config::MachineLocation::Specific {
|
config::MachineLocation::Network {
|
||||||
network: _,
|
network: _,
|
||||||
address4,
|
address4,
|
||||||
address6,
|
address6,
|
||||||
@ -70,6 +70,9 @@ impl MachineState {
|
|||||||
network_state.is_ipv6() && address6.is_some(),
|
network_state.is_ipv6() && address6.is_some(),
|
||||||
address6,
|
address6,
|
||||||
),
|
),
|
||||||
|
config::MachineLocation::Blueprint { blueprint: _ } => {
|
||||||
|
(network_state.is_ipv4(), None, network_state.is_ipv6(), None)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if allocate_v4 {
|
if allocate_v4 {
|
||||||
@ -163,6 +166,10 @@ impl MachineState {
|
|||||||
self.unlocked_inner.name.clone()
|
self.unlocked_inner.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn def(&self) -> &config::Machine {
|
||||||
|
&self.unlocked_inner.machine_def
|
||||||
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> MachineId {
|
pub fn id(&self) -> MachineId {
|
||||||
self.unlocked_inner.id
|
self.unlocked_inner.id
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,10 @@ impl NetworkState {
|
|||||||
self.unlocked_inner.name.clone()
|
self.unlocked_inner.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn def(&self) -> &config::Network {
|
||||||
|
&self.unlocked_inner.network_def
|
||||||
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> NetworkId {
|
pub fn id(&self) -> NetworkId {
|
||||||
self.unlocked_inner.id
|
self.unlocked_inner.id
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@ struct TemplateStateUnlockedInner {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct TemplateStateInner {
|
struct TemplateStateInner {
|
||||||
limit_machine_count: u32,
|
limit_machine_count: Option<u32>,
|
||||||
|
limit_machines_per_network: u32,
|
||||||
machines: HashSet<MachineId>,
|
machines: HashSet<MachineId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,15 +25,22 @@ impl TemplateState {
|
|||||||
name: String,
|
name: String,
|
||||||
template_def: config::Template,
|
template_def: config::Template,
|
||||||
) -> MachineRegistryResult<TemplateState> {
|
) -> MachineRegistryResult<TemplateState> {
|
||||||
let limit_machine_count = *machine_registry_inner
|
let limit_machine_count = template_def.limits.machine_count.as_ref().map(|mc| {
|
||||||
|
*machine_registry_inner
|
||||||
|
.unlocked_inner
|
||||||
|
.srng
|
||||||
|
.weighted_choice(mc)
|
||||||
|
});
|
||||||
|
let limit_machines_per_network = *machine_registry_inner
|
||||||
.unlocked_inner
|
.unlocked_inner
|
||||||
.srng
|
.srng
|
||||||
.weighted_choice(&template_def.limits.machine_count);
|
.weighted_choice(&template_def.limits.machines_per_network);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
unlocked_inner: Arc::new(TemplateStateUnlockedInner { name, template_def }),
|
unlocked_inner: Arc::new(TemplateStateUnlockedInner { name, template_def }),
|
||||||
inner: Arc::new(Mutex::new(TemplateStateInner {
|
inner: Arc::new(Mutex::new(TemplateStateInner {
|
||||||
limit_machine_count,
|
limit_machine_count,
|
||||||
|
limit_machines_per_network,
|
||||||
machines: HashSet::new(),
|
machines: HashSet::new(),
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
@ -42,8 +50,116 @@ impl TemplateState {
|
|||||||
self.unlocked_inner.name.clone()
|
self.unlocked_inner.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_active(&self) -> MachineRegistryResult<bool> {
|
pub fn def(&self) -> &config::Template {
|
||||||
|
&self.unlocked_inner.template_def
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_active(
|
||||||
|
&self,
|
||||||
|
machine_registry_inner: &mut MachineRegistryInner,
|
||||||
|
) -> MachineRegistryResult<bool> {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
Ok(inner.machines.len() < inner.limit_machine_count.try_into().unwrap_or(usize::MAX))
|
if let Some(limit_machine_count) = inner.limit_machine_count {
|
||||||
|
if inner.machines.len() < limit_machine_count.try_into().unwrap_or(usize::MAX) {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.def().location.clone() {
|
||||||
|
config::TemplateLocation::Network { network } => {
|
||||||
|
// Filter the weighted list of networks to those that are still active or not yet started and can allocate
|
||||||
|
if network
|
||||||
|
.try_filter(|n| {
|
||||||
|
machine_registry_inner
|
||||||
|
.get_network_state_by_name(&n)
|
||||||
|
.clone()
|
||||||
|
.map(|ns| ns.is_active())
|
||||||
|
.unwrap_or(Ok(true))
|
||||||
|
})?
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
config::TemplateLocation::Blueprint { blueprint } => {
|
||||||
|
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
||||||
|
if blueprint
|
||||||
|
.try_filter(|b| {
|
||||||
|
machine_registry_inner
|
||||||
|
.get_blueprint_state(&b)
|
||||||
|
.clone()
|
||||||
|
.map(|bs| bs.is_active(machine_registry_inner))
|
||||||
|
.unwrap_or(Ok(true))
|
||||||
|
})?
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn instantiate(
|
||||||
|
&self,
|
||||||
|
machine_registry_inner: &mut MachineRegistryInner,
|
||||||
|
) -> MachineRegistryResult<config::Machine> {
|
||||||
|
// Pick or instantiate an available network
|
||||||
|
let location = match self.def().location.clone() {
|
||||||
|
config::TemplateLocation::Network { network } => {
|
||||||
|
// Filter the weighted list of networks to those that are still active or not yet started and can allocate
|
||||||
|
let Some(active_networks) = network.try_filter(|n| {
|
||||||
|
machine_registry_inner
|
||||||
|
.get_network_state_by_name(&n)
|
||||||
|
.clone()
|
||||||
|
.map(|ns| ns.is_active())
|
||||||
|
.unwrap_or(Ok(true))
|
||||||
|
})?
|
||||||
|
else {
|
||||||
|
return Err(MachineRegistryError::NetworkComplete);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Weighted choice of network now that we have a candidate list
|
||||||
|
let network_name = machine_registry_inner
|
||||||
|
.unlocked_inner
|
||||||
|
.srng
|
||||||
|
.weighted_choice(&active_networks);
|
||||||
|
config::MachineLocation::Network {
|
||||||
|
network: network_name.clone(),
|
||||||
|
address4: None,
|
||||||
|
address6: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config::TemplateLocation::Blueprint { blueprint } => {
|
||||||
|
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
||||||
|
let Some(active_blueprints) = blueprint.try_filter(|b| {
|
||||||
|
machine_registry_inner
|
||||||
|
.get_blueprint_state(&b)
|
||||||
|
.clone()
|
||||||
|
.map(|bs| bs.is_active(machine_registry_inner))
|
||||||
|
.unwrap_or(Ok(true))
|
||||||
|
})?
|
||||||
|
else {
|
||||||
|
return Err(MachineRegistryError::BlueprintComplete);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Weighted choice of blueprint now that we have a candidate list
|
||||||
|
let blueprint_name = machine_registry_inner
|
||||||
|
.unlocked_inner
|
||||||
|
.srng
|
||||||
|
.weighted_choice(&active_blueprints);
|
||||||
|
|
||||||
|
config::MachineLocation::Blueprint {
|
||||||
|
blueprint: blueprint_name.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(config::Machine {
|
||||||
|
location,
|
||||||
|
disable_capabilities: self.def().disable_capabilities.clone(),
|
||||||
|
bootstrap: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user