mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-01-13 08:19:47 -05:00
[skip ci]
checkpoint
This commit is contained in:
parent
1c327fca00
commit
29f1e2da11
@ -103,6 +103,33 @@ impl<T: fmt::Debug + Clone> WeightedList<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_filter<F, E>(&self, mut filter: F) -> Result<Option<WeightedList<T>>, E>
|
||||
where
|
||||
F: FnMut(&T) -> Result<bool, E>,
|
||||
{
|
||||
match self {
|
||||
WeightedList::Single(v) => {
|
||||
if filter(v)? {
|
||||
return Ok(Some(self.clone()));
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
WeightedList::List(vec) => {
|
||||
let mut out = Vec::<Weighted<T>>::with_capacity(vec.len());
|
||||
for v in vec {
|
||||
if filter(v.item())? {
|
||||
out.push(v.clone());
|
||||
}
|
||||
}
|
||||
if out.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(WeightedList::List(out)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Probability = f32;
|
||||
@ -174,7 +201,7 @@ pub enum Instance {
|
||||
)]
|
||||
pub struct Machine {
|
||||
#[serde(flatten)]
|
||||
#[validate(custom(function = "validate_machine_location_exists", use_context))]
|
||||
#[validate(custom(function = "validate_machine_location", use_context))]
|
||||
pub location: MachineLocation,
|
||||
#[serde(default)]
|
||||
pub disable_capabilities: Vec<String>,
|
||||
@ -183,10 +210,6 @@ pub struct Machine {
|
||||
}
|
||||
|
||||
fn validate_machine(machine: &Machine, _context: &ValidateContext) -> Result<(), ValidationError> {
|
||||
if machine.address4.is_none() && machine.address6.is_none() {
|
||||
return Err(ValidationError::new("badaddr")
|
||||
.with_message("machine must have at least one address".into()));
|
||||
}
|
||||
if machine.disable_capabilities.contains(&("".to_string())) {
|
||||
return Err(ValidationError::new("badcap")
|
||||
.with_message("machine has empty disabled capability".into()));
|
||||
@ -201,11 +224,11 @@ fn validate_machine(machine: &Machine, _context: &ValidateContext) -> Result<(),
|
||||
)]
|
||||
pub struct Template {
|
||||
#[serde(flatten)]
|
||||
#[validate(custom(function = "validate_template_location_exists", use_context))]
|
||||
#[validate(custom(function = "validate_template_location", use_context))]
|
||||
pub location: TemplateLocation,
|
||||
#[serde(flatten)]
|
||||
#[validate(nested)]
|
||||
pub limits: Limits,
|
||||
pub limits: TemplateLimits,
|
||||
#[serde(default)]
|
||||
pub disable_capabilities: Vec<String>,
|
||||
}
|
||||
@ -222,17 +245,17 @@ fn validate_template(
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
||||
#[validate(schema(function = "validate_limits"))]
|
||||
pub struct Limits {
|
||||
#[validate(schema(function = "validate_template_limits"))]
|
||||
pub struct TemplateLimits {
|
||||
#[validate(nested)]
|
||||
pub machine_count: WeightedList<u32>,
|
||||
}
|
||||
|
||||
fn validate_limits(limits: &Limits) -> Result<(), ValidationError> {
|
||||
fn validate_template_limits(limits: &TemplateLimits) -> Result<(), ValidationError> {
|
||||
limits.machine_count.try_for_each(|x| {
|
||||
if *x == 0 {
|
||||
return Err(ValidationError::new("badcount")
|
||||
.with_message("limits has zero machine count".into()));
|
||||
.with_message("template limits has zero machine count".into()));
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
@ -250,12 +273,27 @@ pub enum MachineLocation {
|
||||
#[serde(default)]
|
||||
address6: Option<Ipv6Addr>,
|
||||
},
|
||||
Network {
|
||||
network: WeightedList<String>,
|
||||
},
|
||||
Blueprint {
|
||||
blueprint: WeightedList<String>,
|
||||
},
|
||||
}
|
||||
|
||||
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)]
|
||||
@ -265,6 +303,22 @@ pub enum TemplateLocation {
|
||||
Blueprint { blueprint: WeightedList<String> },
|
||||
}
|
||||
|
||||
fn validate_template_location(
|
||||
value: &TemplateLocation,
|
||||
context: &ValidateContext,
|
||||
) -> Result<(), ValidationError> {
|
||||
match value {
|
||||
TemplateLocation::Network { network } => {
|
||||
network.try_for_each(|m| validate_network_exists(m, context))?;
|
||||
}
|
||||
TemplateLocation::Blueprint { blueprint } => {
|
||||
blueprint.try_for_each(|t| validate_blueprint_exists(t, context))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
||||
@ -355,6 +409,8 @@ pub struct Blueprint {
|
||||
#[serde(default)]
|
||||
#[validate(custom(function = "validate_models_exist", use_context))]
|
||||
pub model: Option<WeightedList<String>>,
|
||||
#[validate(nested)]
|
||||
pub limits: BlueprintLimits,
|
||||
#[serde(default)]
|
||||
#[validate(custom(function = "validate_blueprint_ipv4", use_context))]
|
||||
pub ipv4: Option<BlueprintIpv4>,
|
||||
@ -374,6 +430,25 @@ fn validate_blueprint(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
|
||||
#[validate(schema(function = "validate_blueprint_limits"))]
|
||||
pub struct BlueprintLimits {
|
||||
#[validate(nested)]
|
||||
pub network_count: WeightedList<u32>,
|
||||
}
|
||||
|
||||
fn validate_blueprint_limits(limits: &BlueprintLimits) -> Result<(), ValidationError> {
|
||||
limits.network_count.try_for_each(|x| {
|
||||
if *x == 0 {
|
||||
return Err(ValidationError::new("badcount")
|
||||
.with_message("blueprint limits has zero machine count".into()));
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BlueprintIpv4 {
|
||||
#[serde(default)]
|
||||
@ -635,49 +710,6 @@ fn validate_instances_exist(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_machine_location_exists(
|
||||
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)?;
|
||||
}
|
||||
MachineLocation::Network { network } => {
|
||||
network.try_for_each(|n| validate_network_exists(n, context))?;
|
||||
}
|
||||
MachineLocation::Blueprint { blueprint } => {
|
||||
blueprint.try_for_each(|b| validate_blueprint_exists(b, context))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_template_location_exists(
|
||||
value: &TemplateLocation,
|
||||
context: &ValidateContext,
|
||||
) -> Result<(), ValidationError> {
|
||||
match value {
|
||||
TemplateLocation::Network { network } => {
|
||||
network.try_for_each(|m| validate_network_exists(m, context))?;
|
||||
}
|
||||
TemplateLocation::Blueprint { blueprint } => {
|
||||
blueprint.try_for_each(|t| validate_blueprint_exists(t, context))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_network_exists(value: &str, context: &ValidateContext) -> Result<(), ValidationError> {
|
||||
if !context.config.networks.contains_key(value) {
|
||||
return Err(ValidationError::new("noexist").with_message("network does not exist".into()));
|
||||
|
@ -54,24 +54,23 @@ impl MachineRegistryInner {
|
||||
.or_insert_with(|| ProfileState::default());
|
||||
|
||||
// Get the next instance from the definition
|
||||
let Some(instance_def) = profile_def
|
||||
.instances
|
||||
.get(profile_state.next_instance_index)
|
||||
let Some(instance_def) = profile_def.instances.get(profile_state.next_instance_index)
|
||||
else {
|
||||
//
|
||||
return Err(MachineRegistryError::ProfileComplete);
|
||||
};
|
||||
|
||||
match instance_def {
|
||||
let machine_state = match instance_def {
|
||||
config::Instance::Machine { machine } => {
|
||||
let machine = self.unlocked_inner.srng.weighted_choice(machine);
|
||||
let unlocked_inner = self.unlocked_inner.clone();
|
||||
let machine_def = unlocked_inner
|
||||
.config
|
||||
.machines
|
||||
.get(machine).cloned()
|
||||
.get(machine)
|
||||
.cloned()
|
||||
.expect("config validation is broken");
|
||||
self.get_or_create_machine_state_id(machine.clone(), machine_def)
|
||||
self.get_or_create_machine_state(machine.clone(), machine_def)?
|
||||
}
|
||||
config::Instance::Template { template } => {
|
||||
let template = self.unlocked_inner.srng.weighted_choice(template);
|
||||
@ -79,31 +78,36 @@ impl MachineRegistryInner {
|
||||
let template_def = unlocked_inner
|
||||
.config
|
||||
.templates
|
||||
.get(template).cloned()
|
||||
.get(template)
|
||||
.cloned()
|
||||
.expect("config validation is broken");
|
||||
self.create_machine_state_from_template(template.clone(), template_def)
|
||||
self.get_or_create_machine_state_from_template(template.clone(), template_def)?
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(machine_state.id())
|
||||
}
|
||||
|
||||
pub fn release(&self, machine_id: MachineId) -> MachineRegistryResult<()> {
|
||||
// xxx
|
||||
// xxx remember machines and networks may not be 'named' if they are generated by templates and blueprints
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
/// Private Implementation
|
||||
|
||||
pub(super) fn get_or_create_machine_state_id(
|
||||
pub(super) fn get_or_create_machine_state(
|
||||
&mut self,
|
||||
name: String,
|
||||
machine_def: config::Machine,
|
||||
) -> MachineRegistryResult<MachineId> {
|
||||
|
||||
) -> MachineRegistryResult<MachineState> {
|
||||
// Ensure we don't already have this machine created (name must be unique)
|
||||
if let Some(machine_id) = self.resolve_to_manager_machine.add(name.clone()).get() {
|
||||
return Ok(machine_id);
|
||||
return Ok(self
|
||||
.machine_state_by_id
|
||||
.get(&machine_id)
|
||||
.cloned()
|
||||
.expect("must exist"));
|
||||
}
|
||||
|
||||
// Allocate a machine id
|
||||
@ -114,9 +118,211 @@ impl MachineRegistryInner {
|
||||
});
|
||||
|
||||
// Create a new machine state
|
||||
let machine_state = match MachineState::try_new(self,
|
||||
let machine_state = match MachineState::try_new(
|
||||
self,
|
||||
machine_id,
|
||||
MachineStateName::Machine(name.clone()),
|
||||
machine_def.clone(),
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
// Release the machine id
|
||||
self.free_machine_ids.push(machine_id);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the machine state with its unique id
|
||||
self.machine_state_by_id.insert(machine_id, machine_state);
|
||||
|
||||
// Bind the name to the id
|
||||
self.resolve_to_manager_machine
|
||||
.resolve(&name, machine_id)
|
||||
.expect("must resolve");
|
||||
|
||||
// Return the state
|
||||
Ok(self
|
||||
.machine_state_by_id
|
||||
.get(&machine_id)
|
||||
.cloned()
|
||||
.expect("must exist"))
|
||||
}
|
||||
|
||||
pub(super) fn get_machine_state_by_id(
|
||||
&mut self,
|
||||
machine_id: MachineId,
|
||||
) -> MachineRegistryResult<&mut MachineState> {
|
||||
self.machine_state_by_id
|
||||
.get_mut(&machine_id)
|
||||
.ok_or_else(|| MachineRegistryError::MachineNotFound)
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_network_state(
|
||||
&mut self,
|
||||
name: String,
|
||||
network_def: config::Network,
|
||||
) -> MachineRegistryResult<NetworkState> {
|
||||
// Ensure we don't already have this network created (name must be unique)
|
||||
if let Some(network_id) = self.resolve_to_manager_network.add(name.clone()).get() {
|
||||
return Ok(self
|
||||
.network_state_by_id
|
||||
.get(&network_id)
|
||||
.cloned()
|
||||
.expect("must exist"));
|
||||
}
|
||||
|
||||
// Allocate a network id
|
||||
let network_id = self.free_network_ids.pop().unwrap_or_else(|| {
|
||||
let x = self.next_network_id;
|
||||
self.next_network_id += 1;
|
||||
x
|
||||
});
|
||||
|
||||
// Create a new network state
|
||||
let network_state = match NetworkState::try_new(
|
||||
self,
|
||||
network_id,
|
||||
NetworkStateName::Network(name.clone()),
|
||||
network_def.clone(),
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
// Release the network id
|
||||
self.free_network_ids.push(network_id);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the network state with its unique id
|
||||
self.network_state_by_id.insert(network_id, network_state);
|
||||
|
||||
// Bind the name to the id
|
||||
self.resolve_to_manager_network
|
||||
.resolve(&name, network_id)
|
||||
.expect("must resolve");
|
||||
|
||||
// Return the unique id
|
||||
Ok(self
|
||||
.network_state_by_id
|
||||
.get(&network_id)
|
||||
.cloned()
|
||||
.expect("must exist"))
|
||||
}
|
||||
|
||||
pub(super) fn get_network_state_by_name(&self, name: &String) -> Option<NetworkState> {
|
||||
let network_id = self.resolve_to_manager_network.get(name)?;
|
||||
self.network_state_by_id.get(&network_id).cloned()
|
||||
}
|
||||
|
||||
pub(super) fn get_network_state_by_id(
|
||||
&self,
|
||||
network_id: NetworkId,
|
||||
) -> MachineRegistryResult<NetworkState> {
|
||||
self.network_state_by_id
|
||||
.get(&network_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| MachineRegistryError::NetworkNotFound)
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_template_state(
|
||||
&mut self,
|
||||
name: &String,
|
||||
template_def: config::Template,
|
||||
) -> MachineRegistryResult<&mut TemplateState> {
|
||||
// Ensure we don't already have this template created (name must be unique)
|
||||
if self.template_state_by_name.contains_key(name) {
|
||||
return Ok(self
|
||||
.template_state_by_name
|
||||
.get_mut(name)
|
||||
.expect("must exist"));
|
||||
}
|
||||
|
||||
// Create a new template state
|
||||
let template_state = match TemplateState::try_new(self, name.clone(), template_def.clone())
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the template state with its name
|
||||
self.template_state_by_name
|
||||
.insert(name.clone(), template_state);
|
||||
Ok(self
|
||||
.template_state_by_name
|
||||
.get_mut(name)
|
||||
.expect("must exist"))
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_machine_state_from_template(
|
||||
&mut self,
|
||||
name: String,
|
||||
template_def: config::Template,
|
||||
) -> MachineRegistryResult<MachineState> {
|
||||
// Make machine def from current template state
|
||||
let machine_def = {
|
||||
// Get the active template state
|
||||
let template_state = self.get_or_create_template_state(&name, template_def)?;
|
||||
if !template_state.is_active()? {
|
||||
return Err(MachineRegistryError::TemplateComplete);
|
||||
}
|
||||
|
||||
// Pick or instantiate an available network
|
||||
xxx add 'def()' selector to all types
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
let machine_id = self.free_machine_ids.pop().unwrap_or_else(|| {
|
||||
let x = self.next_machine_id;
|
||||
self.next_machine_id += 1;
|
||||
x
|
||||
});
|
||||
|
||||
// Create a new machine state
|
||||
let machine_state = match MachineState::try_new(
|
||||
self,
|
||||
MachineStateName::Template(name.clone()),
|
||||
machine_def.clone(),
|
||||
machine_id,
|
||||
) {
|
||||
Ok(v) => v,
|
||||
@ -130,172 +336,82 @@ impl MachineRegistryInner {
|
||||
// Store the machine state with its unique id
|
||||
self.machine_state_by_id.insert(machine_id, machine_state);
|
||||
|
||||
// Bind the name to the id
|
||||
self.resolve_to_manager_machine.resolve(&name, machine_id).expect("must resolve");
|
||||
// Add to machines for this template
|
||||
{
|
||||
let template_state = self.get_template_state(&name).expect("must exist");
|
||||
template_state.machines.insert(machine_id);
|
||||
}
|
||||
|
||||
// Return the unique id
|
||||
Ok(machine_id)
|
||||
}
|
||||
|
||||
pub(super) fn get_machine_state_by_id(
|
||||
&mut self,
|
||||
machine_id: MachineId,
|
||||
) -> MachineRegistryResult<&mut MachineState> {
|
||||
self
|
||||
.machine_state_by_id
|
||||
.get_mut(&machine_id).ok_or_else(|| MachineRegistryError::MachineNotFound)
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_network_state_id(
|
||||
&mut self,
|
||||
name: String,
|
||||
network_def: config::Network,
|
||||
) -> MachineRegistryResult<NetworkId> {
|
||||
|
||||
// Ensure we don't already have this network created (name must be unique)
|
||||
if let Some(network_id) = self.resolve_to_manager_network.add(name.clone()).get() {
|
||||
return Ok(network_id);
|
||||
}
|
||||
|
||||
// Allocate a network id
|
||||
let network_id = self.free_network_ids.pop().unwrap_or_else(|| {
|
||||
let x = self.next_network_id;
|
||||
self.next_network_id += 1;
|
||||
x
|
||||
});
|
||||
|
||||
// Create a new network state
|
||||
let network_state = match NetworkState::try_new(self,
|
||||
NetworkStateName::Network(name.clone()),
|
||||
network_def.clone(),
|
||||
network_id,
|
||||
){
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
// Release the network id
|
||||
self.free_network_ids.push(network_id);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the network state with its unique id
|
||||
self.network_state_by_id.insert(network_id, network_state);
|
||||
|
||||
// Bind the name to the id
|
||||
self.resolve_to_manager_network.resolve(&name, network_id).expect("must resolve");
|
||||
|
||||
// Return the unique id
|
||||
Ok(network_id)
|
||||
}
|
||||
|
||||
pub(super) fn get_network_state_by_id (
|
||||
&mut self,
|
||||
network_id: NetworkId,
|
||||
) -> MachineRegistryResult<&mut NetworkState> {
|
||||
self
|
||||
.network_state_by_id
|
||||
.get_mut(&network_id).ok_or_else(|| MachineRegistryError::NetworkNotFound)
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_template_state(
|
||||
&mut self,
|
||||
name: &String,
|
||||
template_def: config::Template,
|
||||
) -> MachineRegistryResult<&mut TemplateState> {
|
||||
|
||||
// Ensure we don't already have this template created (name must be unique)
|
||||
if self.template_state_by_name.contains_key(name) {
|
||||
return Ok(self.template_state_by_name.get_mut(name).expect("must exist"));
|
||||
}
|
||||
|
||||
// Create a new template state
|
||||
let template_state = match TemplateState::try_new(self,
|
||||
name.clone(),
|
||||
template_def.clone(),
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the template state with its name
|
||||
self.template_state_by_name.insert(name.clone(), template_state);
|
||||
Ok(self.template_state_by_name.get_mut(name).expect("must exist"))
|
||||
}
|
||||
|
||||
pub(super) fn create_machine_state_from_template(
|
||||
&mut self,
|
||||
name: String,
|
||||
template_def: config::Template,
|
||||
) -> MachineRegistryResult<MachineId> {
|
||||
|
||||
// Get the active template state
|
||||
let template_state = self.get_or_create_template_state(&name, template_def)?;
|
||||
if !template_state.is_active() {
|
||||
return Err(MachineRegistryError::TemplateComplete);
|
||||
}
|
||||
|
||||
// Make machine def from current template state
|
||||
let machine_def = config::Machine {
|
||||
location: template_state.template_def.location.clone(),
|
||||
address4: template_state.template_def.
|
||||
address6: todo!(),
|
||||
disable_capabilities: todo!(),
|
||||
bootstrap: todo!(),
|
||||
};
|
||||
|
||||
}
|
||||
pub(super) fn get_template_state(
|
||||
&mut self,
|
||||
name: &String,
|
||||
) -> MachineRegistryResult<&mut TemplateState> {
|
||||
self
|
||||
.template_state_by_name
|
||||
.get_mut(name).ok_or_else(|| MachineRegistryError::TemplateNotFound)
|
||||
self.template_state_by_name
|
||||
.get_mut(name)
|
||||
.ok_or_else(|| MachineRegistryError::TemplateNotFound)
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_network_state_from_location(
|
||||
pub(super) fn get_or_create_network_state_from_machine_location(
|
||||
&mut self,
|
||||
location_def: &config::Location,
|
||||
machine_location: &config::MachineLocation,
|
||||
) -> MachineRegistryResult<NetworkState> {
|
||||
match machine_location {
|
||||
config::MachineLocation::Specific {
|
||||
network: name,
|
||||
address4: _,
|
||||
address6: _,
|
||||
} => {
|
||||
let network_def = self
|
||||
.unlocked_inner
|
||||
.config
|
||||
.networks
|
||||
.get(name)
|
||||
.cloned()
|
||||
.expect("config validation is broken");
|
||||
self.get_or_create_network_state(name.clone(), network_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(super) fn get_or_create_network_state_from_template_location(
|
||||
&mut self,
|
||||
template_location: &config::TemplateLocation,
|
||||
) -> MachineRegistryResult<NetworkId> {
|
||||
match location_def {
|
||||
config::Location::Network { network } => {
|
||||
match template_location {
|
||||
config::TemplateLocation::Network { network } => {
|
||||
let name = self.unlocked_inner.srng.weighted_choice(network);
|
||||
let network_def = self
|
||||
.unlocked_inner
|
||||
.config
|
||||
.networks
|
||||
.get(name).cloned()
|
||||
.get(name)
|
||||
.cloned()
|
||||
.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::Location::Blueprint { blueprint } => {
|
||||
config::TemplateLocation::Blueprint { blueprint } => {
|
||||
let name = self.unlocked_inner.srng.weighted_choice(blueprint);
|
||||
let blueprint_def = self
|
||||
.unlocked_inner
|
||||
.config
|
||||
.blueprints
|
||||
.get(name).cloned()
|
||||
.get(name)
|
||||
.cloned()
|
||||
.expect("config validation is broken");
|
||||
self.get_or_create_network_state_from_blueprint(
|
||||
name.clone(),
|
||||
blueprint_def)
|
||||
self.get_or_create_network_state_from_blueprint(name.clone(), blueprint_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(super) fn get_blueprint_state(
|
||||
&mut self,
|
||||
name: &String,
|
||||
) -> MachineRegistryResult<&mut BlueprintState> {
|
||||
self
|
||||
.blueprint_state_by_name
|
||||
.get_mut(name).ok_or_else(|| MachineRegistryError::BlueprintNotFound)
|
||||
self.blueprint_state_by_name
|
||||
.get_mut(name)
|
||||
.ok_or_else(|| MachineRegistryError::BlueprintNotFound)
|
||||
}
|
||||
|
||||
pub(super) fn choose_allocation_v4(
|
||||
@ -379,39 +495,92 @@ impl MachineRegistryInner {
|
||||
// No available allocations left
|
||||
Err(MachineRegistryError::NoAllocation)
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_blueprint_state(
|
||||
&mut self,
|
||||
name: &String,
|
||||
blueprint_def: config::Blueprint,
|
||||
) -> MachineRegistryResult<BlueprintState> {
|
||||
// Ensure we don't already have this blueprint created (name must be unique)
|
||||
if self.blueprint_state_by_name.contains_key(name) {
|
||||
return Ok(self
|
||||
.blueprint_state_by_name
|
||||
.get(name)
|
||||
.cloned()
|
||||
.expect("must exist"));
|
||||
}
|
||||
|
||||
// Create a new blueprint state
|
||||
let blueprint_state =
|
||||
match BlueprintState::try_new(self, name.clone(), blueprint_def.clone()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the blueprint state with its name
|
||||
self.blueprint_state_by_name
|
||||
.insert(name.clone(), blueprint_state);
|
||||
Ok(self
|
||||
.blueprint_state_by_name
|
||||
.get(name)
|
||||
.cloned()
|
||||
.expect("must exist"))
|
||||
}
|
||||
|
||||
pub(super) fn get_or_create_network_state_from_blueprint(
|
||||
&mut self,
|
||||
name: String,
|
||||
blueprint_def: config::Blueprint,
|
||||
) -> MachineRegistryResult<NetworkId> {
|
||||
// Get the active blueprint state
|
||||
let blueprint_state = self.get_or_create_blueprint_state(&name, blueprint_def)?;
|
||||
if !blueprint_state.is_active(self)? {
|
||||
return Err(MachineRegistryError::BlueprintComplete);
|
||||
}
|
||||
|
||||
xxx
|
||||
|
||||
self.with_blueprint_state(
|
||||
name,
|
||||
blueprint_def,
|
||||
|blueprint_state| {
|
||||
// Make network def from current blueprint state
|
||||
let network_def = config::Network {
|
||||
model: blueprint_state
|
||||
.blueprint_def
|
||||
.model
|
||||
.as_ref()
|
||||
.map(|model| self.unlocked_inner.srng.weighted_choice(model).clone()),
|
||||
ipv4: blueprint_state
|
||||
.blueprint_def
|
||||
.ipv4
|
||||
.as_ref()
|
||||
.map(|bpv4| self.unlocked_inner.srng.weighted_choice(bpv4).clone()),
|
||||
ipv6: blueprint_def
|
||||
.ipv6
|
||||
.as_ref()
|
||||
.map(|bpv6| self.unlocked_inner.srng.weighted_choice(bpv6).clone()),
|
||||
};
|
||||
|
||||
//xxx self.
|
||||
//xxx
|
||||
// Make machine def from current template state
|
||||
let machine_def = config::Machine {
|
||||
location: match template_state.template_def.location.clone() {
|
||||
config::TemplateLocation::Network { network } => {
|
||||
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
|
||||
let machine_id = self.free_machine_ids.pop().unwrap_or_else(|| {
|
||||
let x = self.next_machine_id;
|
||||
self.next_machine_id += 1;
|
||||
x
|
||||
});
|
||||
|
||||
// Create a new machine state
|
||||
let machine_state = match MachineState::try_new(
|
||||
self,
|
||||
MachineStateName::Template(name.clone()),
|
||||
machine_def.clone(),
|
||||
machine_id,
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
// Release the machine id
|
||||
self.free_machine_ids.push(machine_id);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the machine state with its unique id
|
||||
self.machine_state_by_id.insert(machine_id, machine_state);
|
||||
|
||||
// Return the unique id
|
||||
Ok(machine_id)
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ pub enum MachineRegistryError {
|
||||
ProfileNotFound,
|
||||
ProfileComplete,
|
||||
TemplateComplete,
|
||||
NetworkComplete,
|
||||
BlueprintComplete,
|
||||
MachineNotFound,
|
||||
NetworkNotFound,
|
||||
|
@ -1,7 +1,63 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlueprintState {
|
||||
pub name: String,
|
||||
pub blueprint_def: config::Blueprint,
|
||||
struct BlueprintStateUnlockedInner {
|
||||
name: String,
|
||||
blueprint_def: config::Blueprint,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BlueprintStateInner {
|
||||
limit_network_count: u32,
|
||||
networks: HashSet<NetworkId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlueprintState {
|
||||
unlocked_inner: Arc<BlueprintStateUnlockedInner>,
|
||||
inner: Arc<Mutex<BlueprintStateInner>>,
|
||||
}
|
||||
|
||||
impl BlueprintState {
|
||||
pub fn try_new(
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
name: String,
|
||||
blueprint_def: config::Blueprint,
|
||||
) -> MachineRegistryResult<BlueprintState> {
|
||||
let limit_network_count = *machine_registry_inner
|
||||
.unlocked_inner
|
||||
.srng
|
||||
.weighted_choice(&blueprint_def.limits.network_count);
|
||||
|
||||
Ok(Self {
|
||||
unlocked_inner: Arc::new(BlueprintStateUnlockedInner {
|
||||
name,
|
||||
blueprint_def,
|
||||
}),
|
||||
inner: Arc::new(Mutex::new(BlueprintStateInner {
|
||||
limit_network_count,
|
||||
networks: HashSet::new(),
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_active(
|
||||
&self,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
) -> MachineRegistryResult<bool> {
|
||||
let inner = self.inner.lock();
|
||||
|
||||
// Check to see if any of our networks are still active, if so the blueprint is still active
|
||||
for network_id in &inner.networks {
|
||||
let network_state = machine_registry_inner
|
||||
.get_network_state_by_id(*network_id)
|
||||
.expect("must exist");
|
||||
if network_state.is_active()? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
||||
// If no existing networks are active, then we see if there's room for another
|
||||
Ok(inner.networks.len() < inner.limit_network_count.try_into().unwrap_or(usize::MAX))
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,48 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MachineStateName {
|
||||
Machine(String),
|
||||
Template(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MachineState {
|
||||
/// The name of this machine state if it was made directly
|
||||
/// or the name of the template used to create it
|
||||
pub name: MachineStateName,
|
||||
/// The definition this machine was created with
|
||||
pub machine_def: config::Machine,
|
||||
struct MachineStateInner {
|
||||
/// The current network interfaces definition
|
||||
pub interfaces: Vec<MachineStateInterface>,
|
||||
interfaces: Vec<MachineStateInterface>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MachineStateInterface {
|
||||
/// The network id
|
||||
/// The network this interface belongs to
|
||||
pub network_id: NetworkId,
|
||||
/// The veilid NetworkInterface state
|
||||
pub network_interface: NetworkInterface,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MachineStateUnlockedInner {
|
||||
/// The id of this machine
|
||||
id: MachineId,
|
||||
/// The name of this machine state if it was made directly
|
||||
/// or the name of the template used to create it
|
||||
name: MachineStateName,
|
||||
/// The definition this machine was created with
|
||||
machine_def: config::Machine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MachineState {
|
||||
unlocked_inner: Arc<MachineStateUnlockedInner>,
|
||||
inner: Arc<Mutex<MachineStateInner>>,
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub fn try_new(
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
id: MachineId,
|
||||
name: MachineStateName,
|
||||
machine_def: config::Machine,
|
||||
machine_id: MachineId,
|
||||
) -> MachineRegistryResult<Self> {
|
||||
// Build list of machinestate interfaces
|
||||
let mut interfaces = Vec::<MachineStateInterface>::new();
|
||||
@ -38,42 +50,31 @@ impl MachineState {
|
||||
// Make default route interface
|
||||
{
|
||||
// Find existing network or create a new one from network or blueprint definition
|
||||
let network_id = machine_registry_inner
|
||||
.get_or_create_network_state_from_location(&machine_def.location)?;
|
||||
let srng = machine_registry_inner.unlocked_inner.srng.clone();
|
||||
let network_state = machine_registry_inner
|
||||
.get_network_state_by_id(network_id)
|
||||
.expect("must exist");
|
||||
.get_or_create_network_state_from_machine_location(&machine_def.location)?;
|
||||
let srng = machine_registry_inner.unlocked_inner.srng.clone();
|
||||
|
||||
// Build list of default route interface addresses
|
||||
let mut addrs = Vec::<InterfaceAddress>::new();
|
||||
|
||||
// Make the default route interface
|
||||
let machine_location = machine_def.location;
|
||||
let machine_location = machine_def.location.clone();
|
||||
let (allocate_v4, opt_address4, allocate_v6, opt_address6) = match machine_location {
|
||||
config::MachineLocation::Specific {
|
||||
network: _,
|
||||
address4,
|
||||
address6,
|
||||
} => (
|
||||
network_state.ipv4.is_some() && address4.is_some(),
|
||||
network_state.is_ipv4() && address4.is_some(),
|
||||
address4,
|
||||
network_state.ipv6.is_some() && address6.is_some(),
|
||||
network_state.is_ipv6() && address6.is_some(),
|
||||
address6,
|
||||
),
|
||||
config::MachineLocation::Network { network: _ }
|
||||
| config::MachineLocation::Blueprint { blueprint: _ } => (
|
||||
network_state.ipv4.is_some(),
|
||||
None,
|
||||
network_state.ipv6.is_some(),
|
||||
None,
|
||||
),
|
||||
};
|
||||
|
||||
if allocate_v4 {
|
||||
let if_addr4 =
|
||||
match network_state.allocate_address_v4(srng.clone(), machine_id, opt_address4)
|
||||
{
|
||||
match network_state.allocate_address_v4(srng.clone(), id, opt_address4) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
network_state
|
||||
@ -93,8 +94,7 @@ impl MachineState {
|
||||
}
|
||||
if allocate_v6 {
|
||||
let if_addr6 =
|
||||
match network_state.allocate_address_v6(srng.clone(), machine_id, opt_address6)
|
||||
{
|
||||
match network_state.allocate_address_v6(srng.clone(), id, opt_address6) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
network_state
|
||||
@ -126,21 +126,28 @@ impl MachineState {
|
||||
};
|
||||
|
||||
interfaces.push(MachineStateInterface {
|
||||
network_id,
|
||||
network_id: network_state.id(),
|
||||
network_interface,
|
||||
});
|
||||
}
|
||||
|
||||
// Create a localhost interface for this machine
|
||||
Ok(Self {
|
||||
name,
|
||||
machine_def,
|
||||
interfaces,
|
||||
unlocked_inner: Arc::new(MachineStateUnlockedInner {
|
||||
id,
|
||||
name,
|
||||
machine_def,
|
||||
}),
|
||||
inner: Arc::new(Mutex::new(MachineStateInner { interfaces })),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn release(self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||
for intf in self.interfaces {
|
||||
pub fn release(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||
let network_states = {
|
||||
let mut inner = self.inner.lock();
|
||||
core::mem::take(&mut inner.interfaces)
|
||||
};
|
||||
for intf in network_states {
|
||||
let network_state = machine_registry_inner
|
||||
.get_network_state_by_id(intf.network_id)
|
||||
.expect("must exist");
|
||||
@ -151,4 +158,12 @@ impl MachineState {
|
||||
.expect("must succeed");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> MachineStateName {
|
||||
self.unlocked_inner.name.clone()
|
||||
}
|
||||
|
||||
pub fn id(&self) -> MachineId {
|
||||
self.unlocked_inner.id
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,37 @@
|
||||
use super::*;
|
||||
use ipnet::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum NetworkStateName {
|
||||
Network(String),
|
||||
Blueprint(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkState {
|
||||
pub struct NetworkStateUnlockedInner {
|
||||
/// The unique id of this network
|
||||
id: NetworkId,
|
||||
/// The name of this network state if it was made directly
|
||||
/// or the name of the blueprint used to create it
|
||||
pub name: NetworkStateName,
|
||||
pub network_def: config::Network,
|
||||
pub model: String,
|
||||
pub ipv4: Option<NetworkStateIpv4>,
|
||||
pub ipv6: Option<NetworkStateIpv6>,
|
||||
name: NetworkStateName,
|
||||
/// The network definition used to create this network
|
||||
network_def: config::Network,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkStateInner {
|
||||
/// The model chosen for this network
|
||||
model: String,
|
||||
/// IPv4 state if it is enabled
|
||||
ipv4: Option<NetworkStateIpv4>,
|
||||
/// IPv6 state if it is enabled
|
||||
ipv6: Option<NetworkStateIpv6>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NetworkState {
|
||||
unlocked_inner: Arc<NetworkStateUnlockedInner>,
|
||||
inner: Arc<Mutex<NetworkStateInner>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -44,9 +60,9 @@ pub type NetworkId = u64;
|
||||
impl NetworkState {
|
||||
pub fn try_new(
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
id: NetworkId,
|
||||
name: NetworkStateName,
|
||||
network_def: config::Network,
|
||||
network_id: NetworkId,
|
||||
) -> MachineRegistryResult<Self> {
|
||||
let model = network_def.model.clone().unwrap_or_else(|| {
|
||||
machine_registry_inner
|
||||
@ -114,21 +130,80 @@ impl NetworkState {
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
network_def,
|
||||
model,
|
||||
ipv4,
|
||||
ipv6,
|
||||
unlocked_inner: Arc::new(NetworkStateUnlockedInner {
|
||||
id,
|
||||
name,
|
||||
network_def,
|
||||
}),
|
||||
inner: Arc::new(Mutex::new(NetworkStateInner { model, ipv4, ipv6 })),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn name(&self) -> NetworkStateName {
|
||||
self.unlocked_inner.name.clone()
|
||||
}
|
||||
|
||||
pub fn id(&self) -> NetworkId {
|
||||
self.unlocked_inner.id
|
||||
}
|
||||
|
||||
pub fn is_ipv4(&self) -> bool {
|
||||
self.inner.lock().ipv4.is_some()
|
||||
}
|
||||
|
||||
pub fn is_ipv6(&self) -> bool {
|
||||
self.inner.lock().ipv6.is_some()
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> MachineRegistryResult<bool> {
|
||||
let inner = self.inner.lock();
|
||||
let mut can_allocate = false;
|
||||
if let Some(network_state_ipv4) = &inner.ipv4 {
|
||||
let hosts_range = network_state_ipv4.allocation.hosts();
|
||||
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
let Some(last_host) = std::iter::Iterator::max(hosts_range) else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
let first_host_bits = first_host.to_bits();
|
||||
let last_host_bits = last_host.to_bits();
|
||||
let count = last_host_bits - first_host_bits + 1;
|
||||
|
||||
if network_state_ipv4.machine_addresses.len() >= count.try_into().unwrap_or(usize::MAX)
|
||||
{
|
||||
can_allocate = false;
|
||||
}
|
||||
};
|
||||
if let Some(network_state_ipv6) = &inner.ipv6 {
|
||||
let hosts_range = network_state_ipv6.allocation.hosts();
|
||||
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
let Some(last_host) = std::iter::Iterator::max(hosts_range) else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
let first_host_bits = first_host.to_bits();
|
||||
let last_host_bits = last_host.to_bits();
|
||||
let count = last_host_bits - first_host_bits + 1;
|
||||
|
||||
if network_state_ipv6.machine_addresses.len() >= count.try_into().unwrap_or(usize::MAX)
|
||||
{
|
||||
can_allocate = false;
|
||||
}
|
||||
};
|
||||
Ok(can_allocate)
|
||||
}
|
||||
|
||||
pub(super) fn allocate_address_v4(
|
||||
&mut self,
|
||||
&self,
|
||||
srng: StableRng,
|
||||
machine_id: MachineId,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
) -> MachineRegistryResult<Ifv4Addr> {
|
||||
let Some(network_state_ipv4) = &mut self.ipv4 else {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
let Some(network_state_ipv4) = &mut inner.ipv4 else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
|
||||
@ -191,8 +266,16 @@ impl NetworkState {
|
||||
Ok(ifaddr)
|
||||
}
|
||||
|
||||
pub(super) fn release_address_v4(&mut self, addr: Ipv4Addr) -> MachineRegistryResult<()> {
|
||||
if let Some(ipv4) = self.ipv4.as_mut() {
|
||||
pub(super) fn release_address_v4(&self, addr: Ipv4Addr) -> MachineRegistryResult<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
Self::release_address_v4_inner(&mut *inner, addr)
|
||||
}
|
||||
|
||||
fn release_address_v4_inner(
|
||||
inner: &mut NetworkStateInner,
|
||||
addr: Ipv4Addr,
|
||||
) -> MachineRegistryResult<()> {
|
||||
if let Some(ipv4) = inner.ipv4.as_mut() {
|
||||
if ipv4.machine_addresses.remove(&addr).is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
@ -200,48 +283,15 @@ impl NetworkState {
|
||||
Err(MachineRegistryError::NoAllocation)
|
||||
}
|
||||
|
||||
pub(super) fn release_address_v6(&mut self, addr: Ipv6Addr) -> MachineRegistryResult<()> {
|
||||
if let Some(ipv6) = self.ipv6.as_mut() {
|
||||
if ipv6.machine_addresses.remove(&addr).is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(MachineRegistryError::NoAllocation)
|
||||
}
|
||||
|
||||
pub(super) fn release_all_addresses<I: Iterator<Item = IpAddr>>(
|
||||
&mut self,
|
||||
addrs: I,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let mut ok = true;
|
||||
for addr in addrs {
|
||||
match addr {
|
||||
IpAddr::V4(ipv4_addr) => {
|
||||
if self.release_address_v4(ipv4_addr).is_err() {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
IpAddr::V6(ipv6_addr) => {
|
||||
if self.release_address_v6(ipv6_addr).is_err() {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(MachineRegistryError::NoAllocation)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn allocate_address_v6(
|
||||
&mut self,
|
||||
&self,
|
||||
srng: StableRng,
|
||||
machine_id: MachineId,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
) -> MachineRegistryResult<Ifv6Addr> {
|
||||
let Some(network_state_ipv6) = &mut self.ipv6 else {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
let Some(network_state_ipv6) = &mut inner.ipv6 else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
|
||||
@ -303,4 +353,48 @@ impl NetworkState {
|
||||
|
||||
Ok(ifaddr)
|
||||
}
|
||||
|
||||
pub(super) fn release_address_v6(&self, addr: Ipv6Addr) -> MachineRegistryResult<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
Self::release_address_v6_inner(&mut *inner, addr)
|
||||
}
|
||||
fn release_address_v6_inner(
|
||||
inner: &mut NetworkStateInner,
|
||||
addr: Ipv6Addr,
|
||||
) -> MachineRegistryResult<()> {
|
||||
if let Some(ipv6) = inner.ipv6.as_mut() {
|
||||
if ipv6.machine_addresses.remove(&addr).is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(MachineRegistryError::NoAllocation)
|
||||
}
|
||||
|
||||
pub(super) fn release_all_addresses<I: Iterator<Item = IpAddr>>(
|
||||
&self,
|
||||
addrs: I,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
let mut ok = true;
|
||||
for addr in addrs {
|
||||
match addr {
|
||||
IpAddr::V4(ipv4_addr) => {
|
||||
if Self::release_address_v4_inner(&mut *inner, ipv4_addr).is_err() {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
IpAddr::V6(ipv6_addr) => {
|
||||
if Self::release_address_v6_inner(&mut *inner, ipv6_addr).is_err() {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(MachineRegistryError::NoAllocation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,4 +69,14 @@ where
|
||||
None => Err(ResolveToError::MissingSymbol),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, symbol: &T) -> Option<I> {
|
||||
self.symbols
|
||||
.get(symbol)
|
||||
.map(|s| {
|
||||
let inner = s.lock();
|
||||
inner.clone()
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,21 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TemplateStateUnlockedInner {
|
||||
name: String,
|
||||
template_def: config::Template,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TemplateStateInner {
|
||||
limit_machine_count: u32,
|
||||
machines: HashSet<MachineId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TemplateState {
|
||||
pub name: String,
|
||||
pub template_def: config::Template,
|
||||
pub limit_machine_count: u32,
|
||||
pub machines: HashSet<MachineId>,
|
||||
unlocked_inner: Arc<TemplateStateUnlockedInner>,
|
||||
inner: Arc<Mutex<TemplateStateInner>>,
|
||||
}
|
||||
|
||||
impl TemplateState {
|
||||
@ -20,14 +30,20 @@ impl TemplateState {
|
||||
.weighted_choice(&template_def.limits.machine_count);
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
template_def,
|
||||
limit_machine_count,
|
||||
machines: HashSet::new(),
|
||||
unlocked_inner: Arc::new(TemplateStateUnlockedInner { name, template_def }),
|
||||
inner: Arc::new(Mutex::new(TemplateStateInner {
|
||||
limit_machine_count,
|
||||
machines: HashSet::new(),
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> bool {
|
||||
self.machines.len() < self.limit_machine_count as usize
|
||||
pub fn name(&self) -> String {
|
||||
self.unlocked_inner.name.clone()
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> MachineRegistryResult<bool> {
|
||||
let inner = self.inner.lock();
|
||||
Ok(inner.machines.len() < inner.limit_machine_count.try_into().unwrap_or(usize::MAX))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user