[skip ci] refactor and make multiple configs possible

This commit is contained in:
Christien Rioux 2025-01-07 20:30:41 -05:00
parent 9e7c41b635
commit d83f09d058
17 changed files with 664 additions and 582 deletions

View File

@ -78,7 +78,11 @@ fn main() -> Result<(), String> {
return Ok(()); return Ok(());
} }
let router_server = virtual_network::RouterServer::new(initial_config); let router_server = virtual_network::RouterServer::new();
if let Err(e) = router_server.execute_config(initial_config) {
xxx continue here
}
let _ss_tcp = if !args.no_tcp { let _ss_tcp = if !args.no_tcp {
Some( Some(

View File

@ -58,9 +58,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
false false
} }
pub fn can_allocate_v6(&self, prefix: u8) -> MachineRegistryResult<bool> { pub fn can_allocate_v6(&self, prefix: u8) -> GlobalStateManagerResult<bool> {
if prefix > 128 { if prefix > 128 {
return Err(MachineRegistryError::InvalidPrefix); return Err(GlobalStateManagerError::InvalidPrefix(prefix));
} }
let mut srng = StableRng::new(0); let mut srng = StableRng::new(0);
@ -68,9 +68,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
Ok(opt_allocation.is_some()) Ok(opt_allocation.is_some())
} }
pub fn can_allocate_v4(&self, prefix: u8) -> MachineRegistryResult<bool> { pub fn can_allocate_v4(&self, prefix: u8) -> GlobalStateManagerResult<bool> {
if prefix > 32 { if prefix > 32 {
return Err(MachineRegistryError::InvalidPrefix); return Err(GlobalStateManagerError::InvalidPrefix(prefix));
} }
let mut srng = StableRng::new(0); let mut srng = StableRng::new(0);
@ -82,15 +82,15 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
&mut self, &mut self,
allocation: Ipv4Net, allocation: Ipv4Net,
opt_tag: Option<T>, opt_tag: Option<T>,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
// Ensure the allocation is in our scope // Ensure the allocation is in our scope
if !self.is_in_scope_v4(allocation) { if !self.is_in_scope_v4(allocation) {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
} }
// Only reserve if it's not overlapping an allocation // Only reserve if it's not overlapping an allocation
if !self.get_overlaps_v4(allocation).is_empty() { if !self.get_overlaps_v4(allocation).is_empty() {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
} }
// Add to our allocated pool // Add to our allocated pool
@ -104,15 +104,15 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
&mut self, &mut self,
allocation: Ipv6Net, allocation: Ipv6Net,
opt_tag: Option<T>, opt_tag: Option<T>,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
// Ensure the allocation is in our scope // Ensure the allocation is in our scope
if !self.is_in_scope_v6(allocation) { if !self.is_in_scope_v6(allocation) {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
} }
// Only reserve if it's not overlapping an allocation // Only reserve if it's not overlapping an allocation
if !self.get_overlaps_v6(allocation).is_empty() { if !self.get_overlaps_v6(allocation).is_empty() {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
} }
// Add to our allocated pool // Add to our allocated pool
@ -149,9 +149,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
srng: &mut StableRng, srng: &mut StableRng,
prefix: u8, prefix: u8,
tag: T, tag: T,
) -> MachineRegistryResult<Option<Ipv4Net>> { ) -> GlobalStateManagerResult<Option<Ipv4Net>> {
if prefix > 32 { if prefix > 32 {
return Err(MachineRegistryError::InvalidPrefix); return Err(GlobalStateManagerError::InvalidPrefix(prefix));
} }
let opt_allocation = self.find_random_allocation_v4(srng, prefix); let opt_allocation = self.find_random_allocation_v4(srng, prefix);
@ -173,9 +173,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
srng: &mut StableRng, srng: &mut StableRng,
prefix: u8, prefix: u8,
tag: T, tag: T,
) -> MachineRegistryResult<Option<Ipv6Net>> { ) -> GlobalStateManagerResult<Option<Ipv6Net>> {
if prefix > 128 { if prefix > 128 {
return Err(MachineRegistryError::InvalidPrefix); return Err(GlobalStateManagerError::InvalidPrefix(prefix));
} }
let opt_allocation = self.find_random_allocation_v6(srng, prefix); let opt_allocation = self.find_random_allocation_v6(srng, prefix);
@ -195,13 +195,13 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
pub fn release_allocation_v4( pub fn release_allocation_v4(
&mut self, &mut self,
allocation: Ipv4Net, allocation: Ipv4Net,
) -> MachineRegistryResult<Option<T>> { ) -> GlobalStateManagerResult<Option<T>> {
let Some(pos) = self.allocated_v4.iter().position(|x| *x == allocation) else { let Some(pos) = self.allocated_v4.iter().position(|x| *x == allocation) else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
let Some(opt_tag) = self.owner_tags_v4.remove(&allocation) else { let Some(opt_tag) = self.owner_tags_v4.remove(&allocation) else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
self.allocated_v4.remove(pos); self.allocated_v4.remove(pos);
@ -212,13 +212,13 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
pub fn release_allocation_v6( pub fn release_allocation_v6(
&mut self, &mut self,
allocation: Ipv6Net, allocation: Ipv6Net,
) -> MachineRegistryResult<Option<T>> { ) -> GlobalStateManagerResult<Option<T>> {
let Some(pos) = self.allocated_v6.iter().position(|x| *x == allocation) else { let Some(pos) = self.allocated_v6.iter().position(|x| *x == allocation) else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
let Some(opt_tag) = self.owner_tags_v6.remove(&allocation) else { let Some(opt_tag) = self.owner_tags_v6.remove(&allocation) else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
self.allocated_v4.remove(pos); self.allocated_v4.remove(pos);
@ -264,7 +264,7 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
pub fn clear_ipv4<F: FnMut(Ipv4Net, &T) -> bool>( pub fn clear_ipv4<F: FnMut(Ipv4Net, &T) -> bool>(
&mut self, &mut self,
mut check: F, mut check: F,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
if !self.is_ipv4() { if !self.is_ipv4() {
return Ok(()); return Ok(());
} }
@ -272,7 +272,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
IpNet::V4(ipv4_net) => check(ipv4_net, t), IpNet::V4(ipv4_net) => check(ipv4_net, t),
IpNet::V6(_ipv6_net) => false, IpNet::V6(_ipv6_net) => false,
}) { }) {
return Err(MachineRegistryError::ResourceInUse); return Err(GlobalStateManagerError::ResourceInUse(
"AddressPool-v4".to_owned(),
));
} }
assert!(self.owner_tags_v4.is_empty(), "tags should be empty"); assert!(self.owner_tags_v4.is_empty(), "tags should be empty");
self.scope_v4.clear(); self.scope_v4.clear();
@ -284,7 +286,7 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
pub fn clear_ipv6<F: FnMut(Ipv6Net, &T) -> bool>( pub fn clear_ipv6<F: FnMut(Ipv6Net, &T) -> bool>(
&mut self, &mut self,
mut check: F, mut check: F,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
if !self.is_ipv6() { if !self.is_ipv6() {
return Ok(()); return Ok(());
} }
@ -292,7 +294,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
IpNet::V4(_ipv4_net) => false, IpNet::V4(_ipv4_net) => false,
IpNet::V6(ipv6_net) => check(ipv6_net, t), IpNet::V6(ipv6_net) => check(ipv6_net, t),
}) { }) {
return Err(MachineRegistryError::ResourceInUse); return Err(GlobalStateManagerError::ResourceInUse(
"AddressPool-v6".to_owned(),
));
} }
assert!(self.owner_tags_v6.is_empty(), "tags should be empty"); assert!(self.owner_tags_v6.is_empty(), "tags should be empty");
self.scope_v6.clear(); self.scope_v6.clear();

View File

@ -1,73 +1,86 @@
use super::*; use super::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(super) struct MachineRegistryInner { pub(super) struct GlobalStateManagerInner {
unlocked_inner: Arc<MachineRegistryUnlockedInner>, unlocked_inner: Arc<GlobalStateManagerUnlockedInner>,
srng: StableRng, srng: StableRng,
models: imbl::HashMap<String, config::Model>,
allocations: imbl::HashMap<String, config::Allocation>,
allocated_machines: imbl::HashSet<MachineStateId>, allocated_machines: imbl::HashSet<MachineStateId>,
profile_state_allocator: StateAllocator<ProfileState>, profile_state_registry: StateRegistry<ProfileState>,
machine_state_allocator: StateAllocator<MachineState>, machine_state_registry: StateRegistry<MachineState>,
template_state_allocator: StateAllocator<TemplateState>, template_state_registry: StateRegistry<TemplateState>,
network_state_allocator: StateAllocator<NetworkState>, network_state_registry: StateRegistry<NetworkState>,
blueprint_state_allocator: StateAllocator<BlueprintState>, blueprint_state_registry: StateRegistry<BlueprintState>,
} }
impl MachineRegistryInner { impl GlobalStateManagerInner {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
/// Public Interface /// Public Interface
pub fn new(unlocked_inner: Arc<MachineRegistryUnlockedInner>) -> Self { pub fn new(unlocked_inner: Arc<GlobalStateManagerUnlockedInner>) -> Self {
let srng = StableRng::new(unlocked_inner.config.seed.unwrap_or_default()); GlobalStateManagerInner {
MachineRegistryInner {
unlocked_inner, unlocked_inner,
srng, srng: StableRng::new(0),
models: imbl::HashMap::new(),
allocations: imbl::HashMap::new(),
allocated_machines: imbl::HashSet::new(), allocated_machines: imbl::HashSet::new(),
profile_state_allocator: StateAllocator::new(), profile_state_registry: StateRegistry::new(),
machine_state_allocator: StateAllocator::new(), machine_state_registry: StateRegistry::new(),
template_state_allocator: StateAllocator::new(), template_state_registry: StateRegistry::new(),
network_state_allocator: StateAllocator::new(), network_state_registry: StateRegistry::new(),
blueprint_state_allocator: StateAllocator::new(), blueprint_state_registry: StateRegistry::new(),
} }
} }
pub fn srng(&mut self) -> &mut StableRng {
&mut self.srng pub fn execute_config(&mut self, cfg: config::Config) -> GlobalStateManagerResult<()> {
} // Create random number generator
pub fn config(&self) -> &config::Config { if let Some(seed) = cfg.seed {
&self.unlocked_inner.config self.srng = StableRng::new(seed);
} }
pub fn execute_config(&self, cfg: config::Config) -> MachineRegistryResult<()> { // Import all allocation definitions
// Create all networks for a in cfg.allocations {
if self.allocations.contains_key(&a.0) {
return Err(GlobalStateManagerError::DuplicateName(a.0));
}
self.allocations.insert(a.0, a.1);
}
// Create all blueprints // Import all models
for m in cfg.models {
if self.models.contains_key(&m.0) {
return Err(GlobalStateManagerError::DuplicateName(m.0));
}
self.models.insert(m.0, m.1);
}
// Create all templates // Create all profile states
// Create all machines // Create all network states
// Create all blueprint states
// Create all template states
// Create all machine states
Ok(()) Ok(())
} }
pub fn allocate(&mut self, profile: String) -> MachineRegistryResult<MachineId> { pub fn allocate(&mut self, profile: String) -> GlobalStateManagerResult<MachineId> {
// Get profile definition // Get current profile state
let Some(profile_def) = self.unlocked_inner.config.profiles.get(&profile) else { let Some(profile_state_id) = self.profile_state_registry.get_state_id_by_name(&profile)
return Err(MachineRegistryError::ProfileNotFound); else {
return Err(GlobalStateManagerError::ProfileNotFound(profile));
}; };
// Get current profile state, creating one if we have not yet started executing the profile
let profile_state_id = self
.profile_state_allocator
.get_or_create_by_name(profile, |id, name| {
ProfileState::new(id, name, profile_def.clone())
});
// Get the next instance from the definition // Get the next instance from the definition
loop { loop {
// Move to the next profile instance // Move to the next profile instance
let mut profile_state = self.profile_states().get_state(profile_state_id)?; let mut profile_state = self.profile_states().get_state(profile_state_id)?;
let Some(instance_def) = profile_state.next_instance() else { let Some(instance_def) = profile_state.next_instance() else {
return Err(MachineRegistryError::ProfileComplete); return Err(GlobalStateManagerError::ProfileComplete(profile));
}; };
self.profile_states_mut().set_state(profile_state); self.profile_states_mut().set_state(profile_state);
@ -80,7 +93,7 @@ impl MachineRegistryInner {
let Some(machine_state_id) = let Some(machine_state_id) =
self.machine_states().get_state_id_by_name(name) self.machine_states().get_state_id_by_name(name)
else { else {
return Err(MachineRegistryError::MachineNotFound); return Err(GlobalStateManagerError::MachineNotFound(name.clone()));
}; };
if self.allocated_machines.contains(&machine_state_id) { if self.allocated_machines.contains(&machine_state_id) {
Ok(None) Ok(None)
@ -109,7 +122,7 @@ impl MachineRegistryInner {
let Some(template_state_id) = let Some(template_state_id) =
self.template_states().get_state_id_by_name(name) self.template_states().get_state_id_by_name(name)
else { else {
return Err(MachineRegistryError::TemplateNotFound); return Err(GlobalStateManagerError::TemplateNotFound(name.clone()));
}; };
let template_state = self let template_state = self
.template_states() .template_states()
@ -143,7 +156,7 @@ impl MachineRegistryInner {
} }
} }
pub fn release(&mut self, machine_id: MachineId) -> MachineRegistryResult<()> { pub fn release(&mut self, machine_id: MachineId) -> GlobalStateManagerResult<()> {
let id = StateId::<MachineState>::new(machine_id); let id = StateId::<MachineState>::new(machine_id);
if self.allocated_machines.contains(&id) { if self.allocated_machines.contains(&id) {
// Was a fixed machine, so we leave the machine state so it can // Was a fixed machine, so we leave the machine state so it can
@ -162,36 +175,47 @@ impl MachineRegistryInner {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
/// Private Implementation /// Private Implementation
pub(super) fn profile_states(&self) -> &StateAllocator<ProfileState> { pub(super) fn srng(&mut self) -> &mut StableRng {
&self.profile_state_allocator &mut self.srng
}
pub(super) fn machine_states(&self) -> &StateAllocator<MachineState> {
&self.machine_state_allocator
}
pub(super) fn template_states(&self) -> &StateAllocator<TemplateState> {
&self.template_state_allocator
}
pub(super) fn network_states(&self) -> &StateAllocator<NetworkState> {
&self.network_state_allocator
}
pub(super) fn blueprint_states(&self) -> &StateAllocator<BlueprintState> {
&self.blueprint_state_allocator
} }
pub(super) fn profile_states_mut(&mut self) -> &mut StateAllocator<ProfileState> { pub(super) fn models(&self) -> &imbl::HashMap<String, config::Model> {
&mut self.profile_state_allocator &self.models
} }
pub(super) fn machine_states_mut(&mut self) -> &mut StateAllocator<MachineState> { pub(super) fn allocations(&self) -> &imbl::HashMap<String, config::Allocation> {
&mut self.machine_state_allocator &self.allocations
} }
pub(super) fn template_states_mut(&mut self) -> &mut StateAllocator<TemplateState> {
&mut self.template_state_allocator pub(super) fn profile_states(&self) -> &StateRegistry<ProfileState> {
&self.profile_state_registry
} }
pub(super) fn network_states_mut(&mut self) -> &mut StateAllocator<NetworkState> { pub(super) fn machine_states(&self) -> &StateRegistry<MachineState> {
&mut self.network_state_allocator &self.machine_state_registry
} }
pub(super) fn blueprint_states_mut(&mut self) -> &mut StateAllocator<BlueprintState> { pub(super) fn template_states(&self) -> &StateRegistry<TemplateState> {
&mut self.blueprint_state_allocator &self.template_state_registry
}
pub(super) fn network_states(&self) -> &StateRegistry<NetworkState> {
&self.network_state_registry
}
pub(super) fn blueprint_states(&self) -> &StateRegistry<BlueprintState> {
&self.blueprint_state_registry
}
pub(super) fn profile_states_mut(&mut self) -> &mut StateRegistry<ProfileState> {
&mut self.profile_state_registry
}
pub(super) fn machine_states_mut(&mut self) -> &mut StateRegistry<MachineState> {
&mut self.machine_state_registry
}
pub(super) fn template_states_mut(&mut self) -> &mut StateRegistry<TemplateState> {
&mut self.template_state_registry
}
pub(super) fn network_states_mut(&mut self) -> &mut StateRegistry<NetworkState> {
&mut self.network_state_registry
}
pub(super) fn blueprint_states_mut(&mut self) -> &mut StateRegistry<BlueprintState> {
&mut self.blueprint_state_registry
} }
// pub(super) fn get_or_create_machine_state( // pub(super) fn get_or_create_machine_state(

View File

@ -0,0 +1,117 @@
mod address_pool;
mod global_state_manager_inner;
mod state;
use super::*;
use address_pool::*;
use global_state_manager_inner::*;
use state::*;
#[derive(Debug)]
struct Machine {}
#[derive(Debug)]
struct GlobalStateManagerUnlockedInner {}
#[derive(Debug, Clone, ThisError, PartialEq, Eq)]
pub enum GlobalStateManagerError {
#[error("Invalid id: {0}")]
InvalidId(u64),
#[error("Invalid name: {0}")]
InvalidName(String),
#[error("Invalid prefix: {0}")]
InvalidPrefix(u8),
#[error("Already attached")]
AlreadyAttached,
#[error("Not attached")]
NotAttached,
#[error("Duplicate name: {0}")]
DuplicateName(String),
#[error("Profile complete: {0}")]
ProfileComplete(String),
#[error("Template complete: {0}")]
TemplateComplete(String),
#[error("Network complete: {0}")]
NetworkComplete(String),
#[error("Blueprint complete: {0}")]
BlueprintComplete(String),
#[error("Profile not found: {0}")]
ProfileNotFound(String),
#[error("Machine not found: {0}")]
MachineNotFound(String),
#[error("Network not found: {0}")]
NetworkNotFound(String),
#[error("Template not found: {0}")]
TemplateNotFound(String),
#[error("Blueprint not found: {0}")]
BlueprintNotFound(String),
#[error("Model not found: {0}")]
ModelNotFound(String),
#[error("No default model")]
NoDefaultModel,
#[error("No default network")]
NoDefaultNetwork,
#[error("No allocation available")]
NoAllocation,
#[error("Resource in use: {0}")]
ResourceInUse(String),
}
pub type GlobalStateManagerResult<T> = Result<T, GlobalStateManagerError>;
#[derive(Debug, Clone)]
pub struct GlobalStateManager {
unlocked_inner: Arc<GlobalStateManagerUnlockedInner>,
inner: Arc<Mutex<GlobalStateManagerInner>>,
}
impl GlobalStateManager {
///////////////////////////////////////////////////////////
/// Public Interface
pub fn new() -> Self {
let unlocked_inner = Arc::new(GlobalStateManagerUnlockedInner {});
Self {
inner: Arc::new(Mutex::new(GlobalStateManagerInner::new(
unlocked_inner.clone(),
))),
unlocked_inner,
}
}
pub fn execute_config(&self, cfg: config::Config) -> GlobalStateManagerResult<()> {
let mut inner = self.inner.lock();
let saved_state = (*inner).clone();
match inner.execute_config(cfg) {
Ok(v) => Ok(v),
Err(e) => {
*inner = saved_state;
Err(e)
}
}
}
pub fn allocate(&self, profile: String) -> GlobalStateManagerResult<MachineId> {
let mut inner = self.inner.lock();
let saved_state = (*inner).clone();
match inner.allocate(profile) {
Ok(v) => Ok(v),
Err(e) => {
*inner = saved_state;
Err(e)
}
}
}
pub fn release(&self, machine_id: MachineId) -> GlobalStateManagerResult<()> {
let mut inner = self.inner.lock();
let saved_state = (*inner).clone();
match inner.release(machine_id) {
Ok(v) => Ok(v),
Err(e) => {
*inner = saved_state;
Err(e)
}
}
}
}

View File

@ -69,7 +69,7 @@ pub struct BlueprintState {
pub type BlueprintStateId = StateId<BlueprintState>; pub type BlueprintStateId = StateId<BlueprintState>;
impl BlueprintState { impl BlueprintState {
pub fn new(id: BlueprintStateId, name: String) -> MachineRegistryResult<BlueprintState> { pub fn new(id: BlueprintStateId, name: String) -> GlobalStateManagerResult<BlueprintState> {
Ok(Self { Ok(Self {
immutable: Arc::new(BlueprintStateImmutable { id, name }), immutable: Arc::new(BlueprintStateImmutable { id, name }),
fields: Arc::new(BlueprintStateFields { fields: Arc::new(BlueprintStateFields {
@ -165,18 +165,18 @@ impl BlueprintState {
}); });
} }
pub fn is_active(&self, machine_registry_inner: &mut MachineRegistryInner) -> bool { pub fn is_active(&self, gsm_inner: &mut GlobalStateManagerInner) -> bool {
// Save a backup of the entire state // Save a backup of the entire state
let backup = machine_registry_inner.clone(); let backup = gsm_inner.clone();
// Make a copy of this blueprint state // Make a copy of this blueprint state
let mut current_state = self.clone(); let mut current_state = self.clone();
// See what would happen if we try to generate this blueprint // See what would happen if we try to generate this blueprint
let ok = current_state.generate(machine_registry_inner).is_ok(); let ok = current_state.generate(gsm_inner).is_ok();
// Restore the backup // Restore the backup
*machine_registry_inner = backup; *gsm_inner = backup;
// Return if this worked or not // Return if this worked or not
ok ok
@ -184,20 +184,16 @@ impl BlueprintState {
fn generate_model_inner( fn generate_model_inner(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
network_state: &mut NetworkState, network_state: &mut NetworkState,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let model_name = match self.fields.model.as_ref() { let Some(model_list) = self.fields.model.as_ref() else {
Some(models) => (**machine_registry_inner.srng().weighted_choice_ref(models)).clone(), return Err(GlobalStateManagerError::NoDefaultModel);
None => machine_registry_inner
.config()
.default_model
.as_ref()
.ok_or(MachineRegistryError::NoDefaultModel)?
.clone(),
}; };
let Some(model) = machine_registry_inner.config().models.get(&model_name) else { let model_name = (**gsm_inner.srng().weighted_choice_ref(model_list)).clone();
return Err(MachineRegistryError::ModelNotFound);
let Some(model) = gsm_inner.models().get(&model_name) else {
return Err(GlobalStateManagerError::ModelNotFound(model_name));
}; };
let params = NetworkStateModelParams { let params = NetworkStateModelParams {
@ -212,13 +208,11 @@ impl BlueprintState {
/// Network filter that ensures we can allocate an ipv4 gateway address on a network /// Network filter that ensures we can allocate an ipv4 gateway address on a network
fn gateway_network_filter_v4( fn gateway_network_filter_v4(
&self, &self,
machine_registry_inner: &MachineRegistryInner, gsm_inner: &GlobalStateManagerInner,
network_state_id: NetworkStateId, network_state_id: NetworkStateId,
) -> MachineRegistryResult<bool> { ) -> GlobalStateManagerResult<bool> {
// Get the network state // Get the network state
let network_state = machine_registry_inner let network_state = gsm_inner.network_states().get_state(network_state_id)?;
.network_states()
.get_state(network_state_id)?;
// See if we can allocate on this network // See if we can allocate on this network
let can_allocate = network_state.can_allocate_address_v4(None); let can_allocate = network_state.can_allocate_address_v4(None);
@ -229,13 +223,11 @@ impl BlueprintState {
/// Network filter that ensures we can allocate an ipv4 gateway address on a network /// Network filter that ensures we can allocate an ipv4 gateway address on a network
fn gateway_network_filter_v6( fn gateway_network_filter_v6(
&self, &self,
machine_registry_inner: &MachineRegistryInner, gsm_inner: &GlobalStateManagerInner,
network_state_id: NetworkStateId, network_state_id: NetworkStateId,
) -> MachineRegistryResult<bool> { ) -> GlobalStateManagerResult<bool> {
// Get the network state // Get the network state
let network_state = machine_registry_inner let network_state = gsm_inner.network_states().get_state(network_state_id)?;
.network_states()
.get_state(network_state_id)?;
// See if we can allocate on this network // See if we can allocate on this network
let can_allocate = network_state.can_allocate_address_v6(None); let can_allocate = network_state.can_allocate_address_v6(None);
@ -245,19 +237,24 @@ impl BlueprintState {
fn generate_ipv4_inner( fn generate_ipv4_inner(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
network_state: &mut NetworkState, network_state: &mut NetworkState,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
network_state.clear_ipv4(machine_registry_inner)?; network_state.clear_ipv4(gsm_inner)?;
let Some(ipv4) = self.fields.ipv4.as_ref() else { let Some(ipv4) = self.fields.ipv4.as_ref() else {
return Ok(()); return Ok(());
}; };
// Get addresses for network // Get addresses for network
let NetworkLocation { subnet, super_net } = ipv4 let Some(NetworkLocation { subnet, super_net }) = ipv4
.params .params
.locations .locations
.pick_v4(machine_registry_inner, &ipv4.params.prefix)?; .pick_v4(gsm_inner, &ipv4.params.prefix)?
else {
return Err(GlobalStateManagerError::BlueprintComplete(
self.debug_name(),
));
};
let params = NetworkStateIpv4Params { let params = NetworkStateIpv4Params {
allocation: subnet, allocation: subnet,
@ -266,35 +263,37 @@ impl BlueprintState {
let gateway_params = match ipv4.gateway.as_ref() { let gateway_params = match ipv4.gateway.as_ref() {
Some(v4gw) => { Some(v4gw) => {
let translation = *machine_registry_inner let translation = *gsm_inner
.srng() .srng()
.weighted_choice_ref(&v4gw.params.translation); .weighted_choice_ref(&v4gw.params.translation);
let upnp = machine_registry_inner let upnp = gsm_inner.srng().probability_test(v4gw.params.upnp);
.srng()
.probability_test(v4gw.params.upnp);
let (external_network, external_address) = match v4gw.params.locations.as_ref() { let (external_network, external_address) = match v4gw.params.locations.as_ref() {
Some(locations_list) => { Some(locations_list) => {
// A external network location was specified, pick one // A external network location was specified, pick one
// Get a network to generate the machine on // Get a network to generate the machine on
let mut gateway_network_state = locations_list.pick( let Some(mut gateway_network_state) = locations_list
machine_registry_inner, .pick(gsm_inner, |gsm_inner, id| {
|machine_registry_inner, id| { self.gateway_network_filter_v4(gsm_inner, id)
self.gateway_network_filter_v4(machine_registry_inner, id) })?
}, else {
)?; return Err(GlobalStateManagerError::BlueprintComplete(
self.debug_name(),
));
};
let gateway_network_state_id = gateway_network_state.id(); let gateway_network_state_id = gateway_network_state.id();
// Allocate an external address on this network // Allocate an external address on this network
let external_interface_address = gateway_network_state let external_interface_address = gateway_network_state
.allocate_address_v4( .allocate_address_v4(
machine_registry_inner, gsm_inner,
OwnerTag::Gateway(network_state.id()), OwnerTag::Gateway(network_state.id()),
None, None,
)?; )?;
// Update the network state // Update the network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(gateway_network_state); .set_state(gateway_network_state);
@ -321,25 +320,30 @@ impl BlueprintState {
None => None, None => None,
}; };
network_state.set_ipv4(machine_registry_inner, params, gateway_params)?; network_state.set_ipv4(gsm_inner, params, gateway_params)?;
Ok(()) Ok(())
} }
fn generate_ipv6_inner( fn generate_ipv6_inner(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
network_state: &mut NetworkState, network_state: &mut NetworkState,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
network_state.clear_ipv6(machine_registry_inner)?; network_state.clear_ipv6(gsm_inner)?;
let Some(ipv6) = self.fields.ipv6.as_ref() else { let Some(ipv6) = self.fields.ipv6.as_ref() else {
return Ok(()); return Ok(());
}; };
// Get addresses for network // Get addresses for network
let NetworkLocation { subnet, super_net } = ipv6 let Some(NetworkLocation { subnet, super_net }) = ipv6
.params .params
.locations .locations
.pick_v6(machine_registry_inner, &ipv6.params.prefix)?; .pick_v6(gsm_inner, &ipv6.params.prefix)?
else {
return Err(GlobalStateManagerError::BlueprintComplete(
self.debug_name(),
));
};
let params = NetworkStateIpv6Params { let params = NetworkStateIpv6Params {
allocation: subnet, allocation: subnet,
@ -348,35 +352,37 @@ impl BlueprintState {
let gateway_params = match ipv6.gateway.as_ref() { let gateway_params = match ipv6.gateway.as_ref() {
Some(v6gw) => { Some(v6gw) => {
let translation = *machine_registry_inner let translation = *gsm_inner
.srng() .srng()
.weighted_choice_ref(&v6gw.params.translation); .weighted_choice_ref(&v6gw.params.translation);
let upnp = machine_registry_inner let upnp = gsm_inner.srng().probability_test(v6gw.params.upnp);
.srng()
.probability_test(v6gw.params.upnp);
let (external_network, external_address) = match v6gw.params.locations.as_ref() { let (external_network, external_address) = match v6gw.params.locations.as_ref() {
Some(locations_list) => { Some(locations_list) => {
// A external network location was specified, pick one // A external network location was specified, pick one
// Get a network to generate the machine on // Get a network to generate the machine on
let mut gateway_network_state = locations_list.pick( let Some(mut gateway_network_state) = locations_list
machine_registry_inner, .pick(gsm_inner, |gsm_inner, id| {
|machine_registry_inner, id| { self.gateway_network_filter_v6(gsm_inner, id)
self.gateway_network_filter_v6(machine_registry_inner, id) })?
}, else {
)?; return Err(GlobalStateManagerError::BlueprintComplete(
self.debug_name(),
));
};
let gateway_network_state_id = gateway_network_state.id(); let gateway_network_state_id = gateway_network_state.id();
// Allocate an external address on this network // Allocate an external address on this network
let external_interface_address = gateway_network_state let external_interface_address = gateway_network_state
.allocate_address_v6( .allocate_address_v6(
machine_registry_inner, gsm_inner,
OwnerTag::Gateway(network_state.id()), OwnerTag::Gateway(network_state.id()),
None, None,
)?; )?;
// Update the network state // Update the network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(gateway_network_state); .set_state(gateway_network_state);
@ -403,37 +409,39 @@ impl BlueprintState {
None => None, None => None,
}; };
network_state.set_ipv6(machine_registry_inner, params, gateway_params)?; network_state.set_ipv6(gsm_inner, params, gateway_params)?;
Ok(()) Ok(())
} }
pub fn generate( pub fn generate(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
) -> MachineRegistryResult<NetworkStateId> { ) -> GlobalStateManagerResult<NetworkStateId> {
// See if there's room for another network // See if there's room for another network
if let Some(limit_network_count) = self.fields.limit_network_count { if let Some(limit_network_count) = self.fields.limit_network_count {
if self.fields.networks.len() >= limit_network_count { if self.fields.networks.len() >= limit_network_count {
return Err(MachineRegistryError::BlueprintComplete); return Err(GlobalStateManagerError::BlueprintComplete(
self.debug_name(),
));
} }
} }
// Allocate a network id // Allocate a network id
let network_state_id = machine_registry_inner.network_states_mut().allocate_id(); let network_state_id = gsm_inner.network_states_mut().allocate_id();
// Create an anonymous network state // Create an anonymous network state
let mut network_state = let mut network_state =
NetworkState::new(network_state_id, None, NetworkOrigin::Blueprint(self.id())); NetworkState::new(network_state_id, None, NetworkOrigin::Blueprint(self.id()));
if let Err(e) = (|| { if let Err(e) = (|| {
self.generate_model_inner(machine_registry_inner, &mut network_state)?; self.generate_model_inner(gsm_inner, &mut network_state)?;
self.generate_ipv4_inner(machine_registry_inner, &mut network_state)?; self.generate_ipv4_inner(gsm_inner, &mut network_state)?;
self.generate_ipv6_inner(machine_registry_inner, &mut network_state)?; self.generate_ipv6_inner(gsm_inner, &mut network_state)?;
Ok(()) Ok(())
})() { })() {
// Release the network state and id if things failed to allocate // Release the network state and id if things failed to allocate
network_state.release(machine_registry_inner); network_state.release(gsm_inner);
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.release_id(network_state_id) .release_id(network_state_id)
.expect("must succeed"); .expect("must succeed");
@ -441,9 +449,7 @@ impl BlueprintState {
} }
// Attach the state to the id // Attach the state to the id
machine_registry_inner gsm_inner.network_states_mut().attach_state(network_state)?;
.network_states_mut()
.attach_state(network_state)?;
// Record the newly instantiated network // Record the newly instantiated network
let mut networks = self.fields.networks.clone(); let mut networks = self.fields.networks.clone();
@ -458,9 +464,9 @@ impl BlueprintState {
Ok(network_state_id) Ok(network_state_id)
} }
pub fn for_each_network_id<F, R>(&self, mut callback: F) -> MachineRegistryResult<Option<R>> pub fn for_each_network_id<F, R>(&self, mut callback: F) -> GlobalStateManagerResult<Option<R>>
where where
F: FnMut(NetworkStateId) -> MachineRegistryResult<Option<R>>, F: FnMut(NetworkStateId) -> GlobalStateManagerResult<Option<R>>,
{ {
for network_id in &self.fields.networks { for network_id in &self.fields.networks {
if let Some(res) = callback(*network_id)? { if let Some(res) = callback(*network_id)? {

View File

@ -20,24 +20,19 @@ pub enum MachineLocationsList {
impl MachineLocationsList { impl MachineLocationsList {
pub fn can_pick<F>( pub fn can_pick<F>(
&self, &self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
mut network_filter: F, mut network_filter: F,
) -> MachineRegistryResult<bool> ) -> GlobalStateManagerResult<bool>
where where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>, F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{ {
match self { match self {
MachineLocationsList::Networks { networks } => { MachineLocationsList::Networks { networks } => {
// Filter the weighted list of networks to those that are still active and or not yet started // Filter the weighted list of networks to those that are still active and or not yet started
if networks if networks
.try_filter(|id| { .try_filter(|id| {
let network_state = let network_state = gsm_inner.network_states().get_state(*id)?;
machine_registry_inner.network_states().get_state(*id)?; self.is_network_available(gsm_inner, network_state, &mut network_filter)
self.is_network_available(
machine_registry_inner,
network_state,
&mut network_filter,
)
})? })?
.is_none() .is_none()
{ {
@ -48,14 +43,9 @@ impl MachineLocationsList {
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate // Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
if blueprints if blueprints
.try_filter(|id| { .try_filter(|id| {
let blueprint_state = let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?;
machine_registry_inner.blueprint_states().get_state(*id)?;
self.is_blueprint_available( self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter)
machine_registry_inner,
blueprint_state,
&mut network_filter,
)
.map(|x| x.is_some()) .map(|x| x.is_some())
})? })?
.is_none() .is_none()
@ -69,20 +59,20 @@ impl MachineLocationsList {
pub fn pick<F>( pub fn pick<F>(
&self, &self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
mut network_filter: F, mut network_filter: F,
) -> MachineRegistryResult<NetworkState> ) -> GlobalStateManagerResult<Option<NetworkState>>
where where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>, F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{ {
// Get a network to generate the machine on // Get a network to generate the machine on
let network_state = match self { let network_state = match self {
MachineLocationsList::Networks { networks } => { MachineLocationsList::Networks { networks } => {
// Filter the weighted list of networks to those that are still active and or not yet started // Filter the weighted list of networks to those that are still active and or not yet started
let Some(available_networks) = networks.try_filter_map(|id| { let Some(available_networks) = networks.try_filter_map(|id| {
let network_state = machine_registry_inner.network_states().get_state(*id)?; let network_state = gsm_inner.network_states().get_state(*id)?;
if self.is_network_available( if self.is_network_available(
machine_registry_inner, gsm_inner,
network_state.clone(), network_state.clone(),
&mut network_filter, &mut network_filter,
)? { )? {
@ -92,13 +82,11 @@ impl MachineLocationsList {
} }
})? })?
else { else {
return Err(MachineRegistryError::NetworkComplete); return Ok(None);
}; };
// Weighted choice of network now that we have a candidate list // Weighted choice of network now that we have a candidate list
let network_state = machine_registry_inner let network_state = gsm_inner.srng().weighted_choice(available_networks);
.srng()
.weighted_choice(available_networks);
// Return network state to use // Return network state to use
network_state network_state
@ -106,54 +94,42 @@ impl MachineLocationsList {
MachineLocationsList::Blueprints { blueprints } => { MachineLocationsList::Blueprints { blueprints } => {
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate // Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
let Some(available_blueprints) = blueprints.try_filter_map(|id| { let Some(available_blueprints) = blueprints.try_filter_map(|id| {
let blueprint_state = let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?;
machine_registry_inner.blueprint_states().get_state(*id)?;
self.is_blueprint_available( self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter)
machine_registry_inner,
blueprint_state,
&mut network_filter,
)
})? })?
else { else {
return Err(MachineRegistryError::BlueprintComplete); return Ok(None);
}; };
// Weighted choice of blueprint now that we have a candidate list // Weighted choice of blueprint now that we have a candidate list
match machine_registry_inner match gsm_inner.srng().weighted_choice(available_blueprints) {
.srng()
.weighted_choice(available_blueprints)
{
BlueprintAvailability::Existing(network_state) => network_state, BlueprintAvailability::Existing(network_state) => network_state,
BlueprintAvailability::Generate(mut blueprint_state) => { BlueprintAvailability::Generate(mut blueprint_state) => {
// Generate network state from blueprint state // Generate network state from blueprint state
let network_state_id = blueprint_state.generate(machine_registry_inner)?; let network_state_id = blueprint_state.generate(gsm_inner)?;
// Update blueprint state // Update blueprint state
machine_registry_inner gsm_inner.blueprint_states_mut().set_state(blueprint_state);
.blueprint_states_mut()
.set_state(blueprint_state);
// Return network state // Return network state
machine_registry_inner gsm_inner.network_states().get_state(network_state_id)?
.network_states()
.get_state(network_state_id)?
} }
} }
} }
}; };
Ok(network_state) Ok(Some(network_state))
} }
fn is_network_available<F>( fn is_network_available<F>(
&self, &self,
machine_registry_inner: &MachineRegistryInner, gsm_inner: &GlobalStateManagerInner,
network_state: NetworkState, network_state: NetworkState,
mut network_filter: F, mut network_filter: F,
) -> MachineRegistryResult<bool> ) -> GlobalStateManagerResult<bool>
where where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>, F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{ {
// If the network is not active, it is not available // If the network is not active, it is not available
if !network_state.is_active()? { if !network_state.is_active()? {
@ -161,7 +137,7 @@ impl MachineLocationsList {
} }
// Check the network filter // Check the network filter
if !network_filter(machine_registry_inner, network_state.id())? { if !network_filter(gsm_inner, network_state.id())? {
return Ok(false); return Ok(false);
} }
@ -170,23 +146,19 @@ impl MachineLocationsList {
fn is_blueprint_available<F>( fn is_blueprint_available<F>(
&self, &self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
blueprint_state: BlueprintState, blueprint_state: BlueprintState,
mut network_filter: F, mut network_filter: F,
) -> MachineRegistryResult<Option<BlueprintAvailability>> ) -> GlobalStateManagerResult<Option<BlueprintAvailability>>
where where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>, F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{ {
// See if the networks generated from this blueprint so far have availability // See if the networks generated from this blueprint so far have availability
// in this template // in this template
if let Some(available_network_state) = blueprint_state.for_each_network_id(|id| { if let Some(available_network_state) = blueprint_state.for_each_network_id(|id| {
// Check the network's availability // Check the network's availability
let network_state = machine_registry_inner.network_states().get_state(id)?; let network_state = gsm_inner.network_states().get_state(id)?;
if self.is_network_available( if self.is_network_available(gsm_inner, network_state.clone(), &mut network_filter)? {
machine_registry_inner,
network_state.clone(),
&mut network_filter,
)? {
// We found one // We found one
return Ok(Some(network_state)); return Ok(Some(network_state));
} }
@ -200,7 +172,7 @@ impl MachineLocationsList {
} }
// If the blueprint is active, it is available because it can make a new network // If the blueprint is active, it is available because it can make a new network
if blueprint_state.is_active(machine_registry_inner) { if blueprint_state.is_active(gsm_inner) {
return Ok(Some(BlueprintAvailability::Generate(blueprint_state))); return Ok(Some(BlueprintAvailability::Generate(blueprint_state)));
} }

View File

@ -60,17 +60,17 @@ impl MachineState {
} }
} }
pub fn release(mut self, machine_registry_inner: &mut MachineRegistryInner) { pub fn release(mut self, gsm_inner: &mut GlobalStateManagerInner) {
self.release_all_interfaces(machine_registry_inner) self.release_all_interfaces(gsm_inner)
.expect("must succeed"); .expect("must succeed");
if let MachineOrigin::Template(generating_template) = self.immutable.origin { if let MachineOrigin::Template(generating_template) = self.immutable.origin {
let mut template_state = machine_registry_inner let mut template_state = gsm_inner
.template_states() .template_states()
.get_state(generating_template) .get_state(generating_template)
.expect("must exist"); .expect("must exist");
template_state.on_machine_released(self.id()); template_state.on_machine_released(self.id());
machine_registry_inner gsm_inner
.template_states_mut() .template_states_mut()
.set_state(template_state); .set_state(template_state);
} }
@ -105,12 +105,14 @@ impl MachineState {
&mut self, &mut self,
interface_name: Option<String>, interface_name: Option<String>,
opt_interface_flags: Option<InterfaceFlags>, opt_interface_flags: Option<InterfaceFlags>,
) -> MachineRegistryResult<Arc<String>> { ) -> GlobalStateManagerResult<Arc<String>> {
let interface_key = interface_name let interface_key = interface_name
.map(Arc::new) .map(Arc::new)
.unwrap_or_else(|| self.next_free_interface_key()); .unwrap_or_else(|| self.next_free_interface_key());
if self.fields.interfaces.contains_key(&interface_key) { if self.fields.interfaces.contains_key(&interface_key) {
return Err(MachineRegistryError::DuplicateName); return Err(GlobalStateManagerError::DuplicateName(
(*interface_key).clone(),
));
} }
let flags = opt_interface_flags.unwrap_or(InterfaceFlags { let flags = opt_interface_flags.unwrap_or(InterfaceFlags {
is_loopback: false, is_loopback: false,
@ -146,35 +148,39 @@ impl MachineState {
pub fn allocate_address_ipv4( pub fn allocate_address_ipv4(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
interface_name: &str, interface_name: &str,
opt_address: Option<Ipv4Addr>, opt_address: Option<Ipv4Addr>,
opt_address_flags: Option<AddressFlags>, opt_address_flags: Option<AddressFlags>,
) -> MachineRegistryResult<Ifv4Addr> { ) -> GlobalStateManagerResult<Ifv4Addr> {
let interface_key = Arc::new(interface_name.to_string()); let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
// Get the network state // Get the network state
let Some(network_id) = machine_state_interface.network_id else { let Some(network_id) = machine_state_interface.network_id else {
return Err(MachineRegistryError::NetworkNotFound); return Err(GlobalStateManagerError::NetworkNotFound(
(*interface_key).clone(),
));
}; };
let mut network_state = machine_registry_inner let mut network_state = gsm_inner
.network_states() .network_states()
.get_state(network_id)?; .get_state(network_id)?;
// Allocate interface address // Allocate interface address
let is_dynamic = opt_address.is_none(); let is_dynamic = opt_address.is_none();
let ifv4_addr = network_state.allocate_address_v4( let ifv4_addr = network_state.allocate_address_v4(
machine_registry_inner, gsm_inner,
OwnerTag::Machine(self.id()), OwnerTag::Machine(self.id()),
opt_address, opt_address,
)?; )?;
// Update the network state // Update the network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(network_state); .set_state(network_state);
@ -212,34 +218,38 @@ impl MachineState {
pub fn allocate_address_ipv6( pub fn allocate_address_ipv6(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
interface_name: &str, interface_name: &str,
opt_address: Option<Ipv6Addr>, opt_address: Option<Ipv6Addr>,
opt_address_flags: Option<AddressFlags>, opt_address_flags: Option<AddressFlags>,
) -> MachineRegistryResult<Ifv6Addr> { ) -> GlobalStateManagerResult<Ifv6Addr> {
let interface_key = Arc::new(interface_name.to_string()); let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
// Get the network state // Get the network state
let Some(network_id) = machine_state_interface.network_id else { let Some(network_id) = machine_state_interface.network_id else {
return Err(MachineRegistryError::NetworkNotFound); return Err(GlobalStateManagerError::NetworkNotFound(
(*interface_key).clone(),
));
}; };
let mut network_state = machine_registry_inner let mut network_state = gsm_inner
.network_states() .network_states()
.get_state(network_id)?; .get_state(network_id)?;
// Allocate interface address // Allocate interface address
let is_dynamic = opt_address.is_none(); let is_dynamic = opt_address.is_none();
let ifv6_addr = network_state.allocate_address_v6( let ifv6_addr = network_state.allocate_address_v6(
machine_registry_inner, gsm_inner,
OwnerTag::Machine(self.id()), OwnerTag::Machine(self.id()),
opt_address, opt_address,
)?; )?;
// Update the network state // Update the network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(network_state); .set_state(network_state);
@ -277,18 +287,20 @@ impl MachineState {
pub fn attach_network( pub fn attach_network(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
interface_name: &str, interface_name: &str,
network_id: NetworkStateId, network_id: NetworkStateId,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let interface_key = Arc::new(interface_name.to_string()); let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
if machine_state_interface.network_id.is_some() { if machine_state_interface.network_id.is_some() {
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?;
} }
machine_state_interface.network_id = Some(network_id); machine_state_interface.network_id = Some(network_id);
@ -310,16 +322,18 @@ impl MachineState {
pub fn detach_network( pub fn detach_network(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
interface_name: &str, interface_name: &str,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let interface_key = Arc::new(interface_name.to_string()); let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?;
// Update interfaces map // Update interfaces map
let interfaces = self let interfaces = self
@ -339,7 +353,7 @@ impl MachineState {
pub fn attached_network_interfaces( pub fn attached_network_interfaces(
&self, &self,
network_id: NetworkStateId, network_id: NetworkStateId,
) -> MachineRegistryResult<Vec<Arc<String>>> { ) -> GlobalStateManagerResult<Vec<Arc<String>>> {
let mut out = Vec::new(); let mut out = Vec::new();
for intf in &self.fields.interfaces { for intf in &self.fields.interfaces {
if intf.1.network_id == Some(network_id) { if intf.1.network_id == Some(network_id) {
@ -351,22 +365,26 @@ impl MachineState {
pub fn release_address( pub fn release_address(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
interface_name: &str, interface_name: &str,
address: IpAddr, address: IpAddr,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let interface_key = Arc::new(interface_name.to_owned()); let interface_key = Arc::new(interface_name.to_owned());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
let Some(network_id) = machine_state_interface.network_id else { let Some(network_id) = machine_state_interface.network_id else {
return Err(MachineRegistryError::NetworkNotFound); return Err(GlobalStateManagerError::NetworkNotFound(
(*interface_key).clone(),
));
}; };
// Get the network state // Get the network state
let mut network_state = machine_registry_inner let mut network_state = gsm_inner
.network_states() .network_states()
.get_state(network_id)?; .get_state(network_id)?;
@ -377,7 +395,7 @@ impl MachineState {
}; };
// Update the network state // Update the network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(network_state); .set_state(network_state);
@ -413,16 +431,18 @@ impl MachineState {
pub fn release_all_addresses( pub fn release_all_addresses(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
interface_name: &str, interface_name: &str,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let interface_key = Arc::new(interface_name.to_string()); let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
Self::release_all_addresses_inner(machine_registry_inner, &mut machine_state_interface)?; Self::release_all_addresses_inner(gsm_inner, &mut machine_state_interface)?;
// Update interfaces map // Update interfaces map
let interfaces = self let interfaces = self
@ -442,24 +462,24 @@ impl MachineState {
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
fn detach_network_inner( fn detach_network_inner(
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
machine_state_interface: &mut MachineStateInterface, machine_state_interface: &mut MachineStateInterface,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
Self::release_all_addresses_inner(machine_registry_inner, machine_state_interface)?; Self::release_all_addresses_inner(gsm_inner, machine_state_interface)?;
machine_state_interface.network_id = None; machine_state_interface.network_id = None;
Ok(()) Ok(())
} }
fn release_all_addresses_inner( fn release_all_addresses_inner(
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
machine_state_interface: &mut MachineStateInterface, machine_state_interface: &mut MachineStateInterface,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let Some(network_id) = machine_state_interface.network_id else { let Some(network_id) = machine_state_interface.network_id else {
return Ok(()); return Ok(());
}; };
// Get the network state // Get the network state
let mut network_state = machine_registry_inner let mut network_state = gsm_inner
.network_states() .network_states()
.get_state(network_id)?; .get_state(network_id)?;
@ -472,7 +492,7 @@ impl MachineState {
} }
// Update the network state // Update the network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(network_state); .set_state(network_state);
@ -488,16 +508,18 @@ impl MachineState {
pub fn release_interface( pub fn release_interface(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
interface_name: &str, interface_name: &str,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let interface_key = Arc::new(interface_name.to_string()); let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?;
// Update interfaces map // Update interfaces map
let interfaces = self.fields.interfaces.without(&interface_key); let interfaces = self.fields.interfaces.without(&interface_key);
@ -513,8 +535,8 @@ impl MachineState {
pub fn release_all_interfaces( pub fn release_all_interfaces(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let interface_names: Vec<String> = self let interface_names: Vec<String> = self
.fields .fields
.interfaces .interfaces
@ -526,10 +548,12 @@ impl MachineState {
let Some(mut machine_state_interface) = let Some(mut machine_state_interface) =
self.fields.interfaces.get(&interface_key).cloned() self.fields.interfaces.get(&interface_key).cloned()
else { else {
return Err(MachineRegistryError::InvalidName); return Err(GlobalStateManagerError::InvalidName(
(*interface_key).clone(),
));
}; };
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?;
} }
// Update fields // Update fields

View File

@ -4,7 +4,7 @@ mod machine_state;
mod network_locations_list; mod network_locations_list;
mod network_state; mod network_state;
mod profile_state; mod profile_state;
mod state_allocator; mod state_registry;
mod template_state; mod template_state;
use super::*; use super::*;
@ -15,5 +15,5 @@ pub use machine_state::*;
pub use network_locations_list::*; pub use network_locations_list::*;
pub use network_state::*; pub use network_state::*;
pub use profile_state::*; pub use profile_state::*;
pub use state_allocator::*; pub use state_registry::*;
pub use template_state::*; pub use template_state::*;

View File

@ -20,9 +20,9 @@ pub struct NetworkLocation<T> {
impl NetworkLocationsList { impl NetworkLocationsList {
pub fn pick_v4( pub fn pick_v4(
&self, &self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
prefix: &WeightedList<u8>, prefix: &WeightedList<u8>,
) -> MachineRegistryResult<NetworkLocation<Ipv4Net>> { ) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv4Net>>> {
// Get maximum prefix // Get maximum prefix
let max_prefix = prefix let max_prefix = prefix
.iter() .iter()
@ -36,9 +36,8 @@ impl NetworkLocationsList {
// Get allocations which have subnets that would fit // Get allocations which have subnets that would fit
// our maximum requested prefix // our maximum requested prefix
let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| { let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| {
let allocation = machine_registry_inner let allocation = gsm_inner
.config() .allocations()
.allocations
.get(allocation_name) .get(allocation_name)
.expect("must exist"); .expect("must exist");
Ok(allocation Ok(allocation
@ -48,48 +47,42 @@ impl NetworkLocationsList {
.and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix))) .and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix)))
})? })?
else { else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
// Pick an allocation // Pick an allocation
let subnets = machine_registry_inner let subnets = gsm_inner.srng().weighted_choice_ref(&alloc_subnets);
.srng()
.weighted_choice_ref(&alloc_subnets);
// Pick a subnet // Pick a subnet
let net = *machine_registry_inner.srng().weighted_choice_ref(subnets); let net = *gsm_inner.srng().weighted_choice_ref(subnets);
// Pick a prefix length that would fit in the subnet // Pick a prefix length that would fit in the subnet
let opt_subnet = prefix let opt_subnet = prefix
.filter(|p| *p >= net.prefix_len()) .filter(|p| *p >= net.prefix_len())
.as_ref() .as_ref()
.map(|wl| { .map(|wl| {
let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
// Use an address pool temporarily to pick a subnet // Use an address pool temporarily to pick a subnet
let mut address_pool = AddressPool::<()>::new(); let mut address_pool = AddressPool::<()>::new();
address_pool.add_scope_v4(net); address_pool.add_scope_v4(net);
address_pool.allocate_random_v4( address_pool.allocate_random_v4(gsm_inner.srng(), subnet_prefix, ())
machine_registry_inner.srng(),
subnet_prefix,
(),
)
}) })
.transpose()? .transpose()?
.flatten(); .flatten();
let Some(subnet) = opt_subnet else { let Some(subnet) = opt_subnet else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
Ok(NetworkLocation { Ok(Some(NetworkLocation {
subnet, subnet,
super_net: None, super_net: None,
}) }))
} }
NetworkLocationsList::Networks { networks } => { NetworkLocationsList::Networks { networks } => {
// Get networks which have subnets that would fit // Get networks which have subnets that would fit
// our maximum requested prefix // our maximum requested prefix
let Some(available_networks) = networks.try_filter(|network_id| { let Some(available_networks) = networks.try_filter(|network_id| {
let super_network_state = machine_registry_inner let super_network_state = gsm_inner
.network_states() .network_states()
.get_state(*network_id) .get_state(*network_id)
.expect("must exist"); .expect("must exist");
@ -97,14 +90,12 @@ impl NetworkLocationsList {
Ok(super_network_state.can_allocate_subnet_v4(None, max_prefix)) Ok(super_network_state.can_allocate_subnet_v4(None, max_prefix))
})? })?
else { else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
// Pick a network // Pick a network
let super_network_id = *machine_registry_inner let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks);
.srng() let mut super_network_state = gsm_inner
.weighted_choice_ref(&available_networks);
let mut super_network_state = machine_registry_inner
.network_states() .network_states()
.get_state(super_network_id) .get_state(super_network_id)
.expect("must exist"); .expect("must exist");
@ -114,11 +105,11 @@ impl NetworkLocationsList {
.filter(|p| super_network_state.can_allocate_subnet_v4(None, *p)) .filter(|p| super_network_state.can_allocate_subnet_v4(None, *p))
.as_ref() .as_ref()
.map(|wl| { .map(|wl| {
let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
// Allocate subnet from this network // Allocate subnet from this network
super_network_state.allocate_subnet_v4( super_network_state.allocate_subnet_v4(
machine_registry_inner, gsm_inner,
OwnerTag::Network(super_network_state.id()), OwnerTag::Network(super_network_state.id()),
None, None,
subnet_prefix, subnet_prefix,
@ -126,27 +117,27 @@ impl NetworkLocationsList {
}) })
.transpose()?; .transpose()?;
let Some(subnet) = opt_subnet else { let Some(subnet) = opt_subnet else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
// Update network state // Update network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(super_network_state); .set_state(super_network_state);
Ok(NetworkLocation { Ok(Some(NetworkLocation {
subnet, subnet,
super_net: Some(super_network_id), super_net: Some(super_network_id),
}) }))
} }
} }
} }
pub fn pick_v6( pub fn pick_v6(
&self, &self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
prefix: &WeightedList<u8>, prefix: &WeightedList<u8>,
) -> MachineRegistryResult<NetworkLocation<Ipv6Net>> { ) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv6Net>>> {
// Get maximum prefix // Get maximum prefix
let max_prefix = prefix let max_prefix = prefix
.iter() .iter()
@ -160,9 +151,8 @@ impl NetworkLocationsList {
// Get allocations which have subnets that would fit // Get allocations which have subnets that would fit
// our maximum requested prefix // our maximum requested prefix
let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| { let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| {
let allocation = machine_registry_inner let allocation = gsm_inner
.config() .allocations()
.allocations
.get(allocation_name) .get(allocation_name)
.expect("must exist"); .expect("must exist");
Ok(allocation Ok(allocation
@ -172,48 +162,42 @@ impl NetworkLocationsList {
.and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix))) .and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix)))
})? })?
else { else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
// Pick an allocation // Pick an allocation
let subnets = machine_registry_inner let subnets = gsm_inner.srng().weighted_choice_ref(&alloc_subnets);
.srng()
.weighted_choice_ref(&alloc_subnets);
// Pick a subnet // Pick a subnet
let net = *machine_registry_inner.srng().weighted_choice_ref(subnets); let net = *gsm_inner.srng().weighted_choice_ref(subnets);
// Pick a prefix length that would fit in the subnet // Pick a prefix length that would fit in the subnet
let opt_subnet = prefix let opt_subnet = prefix
.filter(|p| *p >= net.prefix_len()) .filter(|p| *p >= net.prefix_len())
.as_ref() .as_ref()
.map(|wl| { .map(|wl| {
let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
// Use an address pool temporarily to pick a subnet // Use an address pool temporarily to pick a subnet
let mut address_pool = AddressPool::<()>::new(); let mut address_pool = AddressPool::<()>::new();
address_pool.add_scope_v6(net); address_pool.add_scope_v6(net);
address_pool.allocate_random_v6( address_pool.allocate_random_v6(gsm_inner.srng(), subnet_prefix, ())
machine_registry_inner.srng(),
subnet_prefix,
(),
)
}) })
.transpose()? .transpose()?
.flatten(); .flatten();
let Some(subnet) = opt_subnet else { let Some(subnet) = opt_subnet else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
Ok(NetworkLocation { Ok(Some(NetworkLocation {
subnet, subnet,
super_net: None, super_net: None,
}) }))
} }
NetworkLocationsList::Networks { networks } => { NetworkLocationsList::Networks { networks } => {
// Get networks which have subnets that would fit // Get networks which have subnets that would fit
// our maximum requested prefix // our maximum requested prefix
let Some(available_networks) = networks.try_filter(|network_id| { let Some(available_networks) = networks.try_filter(|network_id| {
let super_network_state = machine_registry_inner let super_network_state = gsm_inner
.network_states() .network_states()
.get_state(*network_id) .get_state(*network_id)
.expect("must exist"); .expect("must exist");
@ -221,14 +205,12 @@ impl NetworkLocationsList {
Ok(super_network_state.can_allocate_subnet_v6(None, max_prefix)) Ok(super_network_state.can_allocate_subnet_v6(None, max_prefix))
})? })?
else { else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
// Pick a network // Pick a network
let super_network_id = *machine_registry_inner let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks);
.srng() let mut super_network_state = gsm_inner
.weighted_choice_ref(&available_networks);
let mut super_network_state = machine_registry_inner
.network_states() .network_states()
.get_state(super_network_id) .get_state(super_network_id)
.expect("must exist"); .expect("must exist");
@ -238,11 +220,11 @@ impl NetworkLocationsList {
.filter(|p| super_network_state.can_allocate_subnet_v6(None, *p)) .filter(|p| super_network_state.can_allocate_subnet_v6(None, *p))
.as_ref() .as_ref()
.map(|wl| { .map(|wl| {
let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
// Allocate subnet from this network // Allocate subnet from this network
super_network_state.allocate_subnet_v6( super_network_state.allocate_subnet_v6(
machine_registry_inner, gsm_inner,
OwnerTag::Network(super_network_state.id()), OwnerTag::Network(super_network_state.id()),
None, None,
subnet_prefix, subnet_prefix,
@ -250,18 +232,18 @@ impl NetworkLocationsList {
}) })
.transpose()?; .transpose()?;
let Some(subnet) = opt_subnet else { let Some(subnet) = opt_subnet else {
return Err(MachineRegistryError::NoAllocation); return Ok(None);
}; };
// Update network state // Update network state
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(super_network_state); .set_state(super_network_state);
Ok(NetworkLocation { Ok(Some(NetworkLocation {
subnet, subnet,
super_net: Some(super_network_id), super_net: Some(super_network_id),
}) }))
} }
} }
} }

View File

@ -137,14 +137,14 @@ impl NetworkState {
} }
} }
pub fn release(self, machine_registry_inner: &mut MachineRegistryInner) { pub fn release(self, gsm_inner: &mut GlobalStateManagerInner) {
if let NetworkOrigin::Blueprint(generating_blueprint) = self.immutable.origin { if let NetworkOrigin::Blueprint(generating_blueprint) = self.immutable.origin {
let mut blueprint_state = machine_registry_inner let mut blueprint_state = gsm_inner
.blueprint_states() .blueprint_states()
.get_state(generating_blueprint) .get_state(generating_blueprint)
.expect("must exist"); .expect("must exist");
blueprint_state.on_network_released(self.id()); blueprint_state.on_network_released(self.id());
machine_registry_inner gsm_inner
.blueprint_states_mut() .blueprint_states_mut()
.set_state(blueprint_state) .set_state(blueprint_state)
} }
@ -159,17 +159,21 @@ impl NetworkState {
pub fn clear_ipv4( pub fn clear_ipv4(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let Some(ipv4) = self.fields.ipv4.clone() else { let Some(ipv4) = self.fields.ipv4.clone() else {
return Ok(()); return Ok(());
}; };
let mut address_pool = self.fields.address_pool.clone(); let mut address_pool = self.fields.address_pool.clone();
address_pool.clear_ipv4(|_n, t| match t { address_pool
.clear_ipv4(|_n, t| match t {
OwnerTag::Machine(_) => true, OwnerTag::Machine(_) => true,
OwnerTag::Network(nsid) => *nsid != self.id(), OwnerTag::Network(nsid) => *nsid != self.id(),
OwnerTag::Gateway(nsid) => *nsid != self.id(), OwnerTag::Gateway(nsid) => *nsid != self.id(),
})
.map_err(|_| {
GlobalStateManagerError::ResourceInUse(format!("{}-v4", self.debug_name()))
})?; })?;
// If we have a gateway, release its external address // If we have a gateway, release its external address
@ -177,7 +181,7 @@ impl NetworkState {
if let Some(gateway) = ipv4.gateway.as_ref() { if let Some(gateway) = ipv4.gateway.as_ref() {
if gateway.params.external_network != self.id() { if gateway.params.external_network != self.id() {
// Get the external network state // Get the external network state
let mut external_network_state = machine_registry_inner let mut external_network_state = gsm_inner
.network_states() .network_states()
.get_state(gateway.params.external_network) .get_state(gateway.params.external_network)
.expect("must succeed"); .expect("must succeed");
@ -188,7 +192,7 @@ impl NetworkState {
.expect("must succeed"); .expect("must succeed");
// Update external network // Update external network
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(external_network_state); .set_state(external_network_state);
} }
@ -206,11 +210,11 @@ impl NetworkState {
pub fn set_ipv4( pub fn set_ipv4(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
params: NetworkStateIpv4Params, params: NetworkStateIpv4Params,
gateway_params: Option<NetworkStateIpv4GatewayParams>, gateway_params: Option<NetworkStateIpv4GatewayParams>,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
self.clear_ipv4(machine_registry_inner)?; self.clear_ipv4(gsm_inner)?;
let mut address_pool = self.fields.address_pool.clone(); let mut address_pool = self.fields.address_pool.clone();
address_pool.add_scope_v4(params.allocation); address_pool.add_scope_v4(params.allocation);
@ -227,12 +231,12 @@ impl NetworkState {
internal_address internal_address
} else { } else {
let Some(internal_address) = address_pool.allocate_random_v4( let Some(internal_address) = address_pool.allocate_random_v4(
machine_registry_inner.srng(), gsm_inner.srng(),
32, 32,
OwnerTag::Gateway(self.id()), OwnerTag::Gateway(self.id()),
)? )?
else { else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
internal_address.addr() internal_address.addr()
}; };
@ -245,7 +249,7 @@ impl NetworkState {
}; };
// Get the external network state // Get the external network state
let mut external_network_state = machine_registry_inner let mut external_network_state = gsm_inner
.network_states() .network_states()
.get_state(gateway_params.external_network) .get_state(gateway_params.external_network)
.expect("must succeed"); .expect("must succeed");
@ -256,7 +260,7 @@ impl NetworkState {
// If the translation mode is 'none', then the external and internal // If the translation mode is 'none', then the external and internal
// addresses must be the same // addresses must be the same
external_network_state.allocate_address_v4( external_network_state.allocate_address_v4(
machine_registry_inner, gsm_inner,
OwnerTag::Gateway(self.id()), OwnerTag::Gateway(self.id()),
Some(internal_address), Some(internal_address),
)? )?
@ -264,14 +268,14 @@ impl NetworkState {
// Network translation means the internal and external addresses // Network translation means the internal and external addresses
// will be different // will be different
external_network_state.allocate_address_v4( external_network_state.allocate_address_v4(
machine_registry_inner, gsm_inner,
OwnerTag::Gateway(self.id()), OwnerTag::Gateway(self.id()),
None, None,
)? )?
}; };
// Update external network // Update external network
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(external_network_state); .set_state(external_network_state);
@ -299,17 +303,21 @@ impl NetworkState {
pub fn clear_ipv6( pub fn clear_ipv6(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
let Some(ipv6) = self.fields.ipv6.clone() else { let Some(ipv6) = self.fields.ipv6.clone() else {
return Ok(()); return Ok(());
}; };
let mut address_pool = self.fields.address_pool.clone(); let mut address_pool = self.fields.address_pool.clone();
address_pool.clear_ipv6(|_n, t| match t { address_pool
.clear_ipv6(|_n, t| match t {
OwnerTag::Machine(_) => true, OwnerTag::Machine(_) => true,
OwnerTag::Network(nsid) => *nsid != self.id(), OwnerTag::Network(nsid) => *nsid != self.id(),
OwnerTag::Gateway(nsid) => *nsid != self.id(), OwnerTag::Gateway(nsid) => *nsid != self.id(),
})
.map_err(|_| {
GlobalStateManagerError::ResourceInUse(format!("{}-v6", self.debug_name()))
})?; })?;
// If we have a gateway, release its external address // If we have a gateway, release its external address
@ -317,7 +325,7 @@ impl NetworkState {
if let Some(gateway) = ipv6.gateway.as_ref() { if let Some(gateway) = ipv6.gateway.as_ref() {
if gateway.params.external_network != self.id() { if gateway.params.external_network != self.id() {
// Get the external network state // Get the external network state
let mut external_network_state = machine_registry_inner let mut external_network_state = gsm_inner
.network_states() .network_states()
.get_state(gateway.params.external_network) .get_state(gateway.params.external_network)
.expect("must succeed"); .expect("must succeed");
@ -328,7 +336,7 @@ impl NetworkState {
.expect("must succeed"); .expect("must succeed");
// Update external network // Update external network
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(external_network_state); .set_state(external_network_state);
} }
@ -345,11 +353,11 @@ impl NetworkState {
} }
pub fn set_ipv6( pub fn set_ipv6(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
params: NetworkStateIpv6Params, params: NetworkStateIpv6Params,
gateway_params: Option<NetworkStateIpv6GatewayParams>, gateway_params: Option<NetworkStateIpv6GatewayParams>,
) -> MachineRegistryResult<()> { ) -> GlobalStateManagerResult<()> {
self.clear_ipv6(machine_registry_inner)?; self.clear_ipv6(gsm_inner)?;
let mut address_pool = self.fields.address_pool.clone(); let mut address_pool = self.fields.address_pool.clone();
address_pool.add_scope_v6(params.allocation); address_pool.add_scope_v6(params.allocation);
@ -366,12 +374,12 @@ impl NetworkState {
internal_address internal_address
} else { } else {
let Some(internal_address) = address_pool.allocate_random_v6( let Some(internal_address) = address_pool.allocate_random_v6(
machine_registry_inner.srng(), gsm_inner.srng(),
128, 128,
OwnerTag::Gateway(self.id()), OwnerTag::Gateway(self.id()),
)? )?
else { else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
internal_address.addr() internal_address.addr()
}; };
@ -384,7 +392,7 @@ impl NetworkState {
}; };
// Get the external network state // Get the external network state
let mut external_network_state = machine_registry_inner let mut external_network_state = gsm_inner
.network_states() .network_states()
.get_state(gateway_params.external_network) .get_state(gateway_params.external_network)
.expect("must succeed"); .expect("must succeed");
@ -395,7 +403,7 @@ impl NetworkState {
// If the translation mode is 'none', then the external and internal // If the translation mode is 'none', then the external and internal
// addresses must be the same // addresses must be the same
external_network_state.allocate_address_v6( external_network_state.allocate_address_v6(
machine_registry_inner, gsm_inner,
OwnerTag::Gateway(self.id()), OwnerTag::Gateway(self.id()),
Some(internal_address), Some(internal_address),
)? )?
@ -403,14 +411,14 @@ impl NetworkState {
// Network translation means the internal and external addresses // Network translation means the internal and external addresses
// will be different // will be different
external_network_state.allocate_address_v6( external_network_state.allocate_address_v6(
machine_registry_inner, gsm_inner,
OwnerTag::Gateway(self.id()), OwnerTag::Gateway(self.id()),
None, None,
)? )?
}; };
// Update external network // Update external network
machine_registry_inner gsm_inner
.network_states_mut() .network_states_mut()
.set_state(external_network_state); .set_state(external_network_state);
@ -444,7 +452,7 @@ impl NetworkState {
self.fields.ipv6.is_some() self.fields.ipv6.is_some()
} }
pub fn is_active(&self) -> MachineRegistryResult<bool> { pub fn is_active(&self) -> GlobalStateManagerResult<bool> {
let mut can_allocate = false; let mut can_allocate = false;
if self.fields.ipv4.is_some() { if self.fields.ipv4.is_some() {
@ -464,11 +472,11 @@ impl NetworkState {
pub fn allocate_address_v4( pub fn allocate_address_v4(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
owner_tag: OwnerTag, owner_tag: OwnerTag,
opt_address: Option<Ipv4Addr>, opt_address: Option<Ipv4Addr>,
) -> MachineRegistryResult<Ifv4Addr> { ) -> GlobalStateManagerResult<Ifv4Addr> {
let net = self.allocate_subnet_v4(machine_registry_inner, owner_tag, opt_address, 32)?; let net = self.allocate_subnet_v4(gsm_inner, owner_tag, opt_address, 32)?;
let ip = net.addr(); let ip = net.addr();
let ipv4 = self.fields.ipv4.as_ref().unwrap(); let ipv4 = self.fields.ipv4.as_ref().unwrap();
@ -490,13 +498,13 @@ impl NetworkState {
pub fn allocate_subnet_v4( pub fn allocate_subnet_v4(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
owner_tag: OwnerTag, owner_tag: OwnerTag,
opt_address: Option<Ipv4Addr>, opt_address: Option<Ipv4Addr>,
prefix: u8, prefix: u8,
) -> MachineRegistryResult<Ipv4Net> { ) -> GlobalStateManagerResult<Ipv4Net> {
if self.fields.ipv4.is_none() { if self.fields.ipv4.is_none() {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
} }
// See if we are requesting a specific address // See if we are requesting a specific address
@ -510,12 +518,12 @@ impl NetworkState {
} else { } else {
// Get a random address if available // Get a random address if available
let Some(allocation) = address_pool.allocate_random_v4( let Some(allocation) = address_pool.allocate_random_v4(
machine_registry_inner.srng(), gsm_inner.srng(),
prefix, prefix,
owner_tag, owner_tag,
)? )?
else { else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
allocation allocation
}; };
@ -551,11 +559,14 @@ impl NetworkState {
pub fn release_address_v4( pub fn release_address_v4(
&mut self, &mut self,
addr: Ipv4Addr, addr: Ipv4Addr,
) -> MachineRegistryResult<Option<OwnerTag>> { ) -> GlobalStateManagerResult<Option<OwnerTag>> {
self.release_subnet_v4(Ipv4Net::new(addr, 32).expect("must succeed")) self.release_subnet_v4(Ipv4Net::new(addr, 32).expect("must succeed"))
} }
pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult<Option<OwnerTag>> { pub fn release_subnet_v4(
&mut self,
net: Ipv4Net,
) -> GlobalStateManagerResult<Option<OwnerTag>> {
let mut address_pool = self.fields.address_pool.clone(); let mut address_pool = self.fields.address_pool.clone();
let opt_tag = address_pool.release_allocation_v4(net)?; let opt_tag = address_pool.release_allocation_v4(net)?;
@ -569,11 +580,11 @@ impl NetworkState {
pub fn allocate_address_v6( pub fn allocate_address_v6(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
owner_tag: OwnerTag, owner_tag: OwnerTag,
opt_address: Option<Ipv6Addr>, opt_address: Option<Ipv6Addr>,
) -> MachineRegistryResult<Ifv6Addr> { ) -> GlobalStateManagerResult<Ifv6Addr> {
let net = self.allocate_subnet_v6(machine_registry_inner, owner_tag, opt_address, 128)?; let net = self.allocate_subnet_v6(gsm_inner, owner_tag, opt_address, 128)?;
let ip = net.addr(); let ip = net.addr();
let ipv6 = self.fields.ipv6.as_ref().unwrap(); let ipv6 = self.fields.ipv6.as_ref().unwrap();
@ -595,13 +606,13 @@ impl NetworkState {
pub fn allocate_subnet_v6( pub fn allocate_subnet_v6(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
owner_tag: OwnerTag, owner_tag: OwnerTag,
opt_address: Option<Ipv6Addr>, opt_address: Option<Ipv6Addr>,
prefix: u8, prefix: u8,
) -> MachineRegistryResult<Ipv6Net> { ) -> GlobalStateManagerResult<Ipv6Net> {
if self.fields.ipv6.is_none() { if self.fields.ipv6.is_none() {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
} }
// See if we are requesting a specific address // See if we are requesting a specific address
@ -615,12 +626,12 @@ impl NetworkState {
} else { } else {
// Get a random address if available // Get a random address if available
let Some(allocation) = address_pool.allocate_random_v6( let Some(allocation) = address_pool.allocate_random_v6(
machine_registry_inner.srng(), gsm_inner.srng(),
prefix, prefix,
owner_tag, owner_tag,
)? )?
else { else {
return Err(MachineRegistryError::NoAllocation); return Err(GlobalStateManagerError::NoAllocation);
}; };
allocation allocation
}; };
@ -656,11 +667,14 @@ impl NetworkState {
pub fn release_address_v6( pub fn release_address_v6(
&mut self, &mut self,
addr: Ipv6Addr, addr: Ipv6Addr,
) -> MachineRegistryResult<Option<OwnerTag>> { ) -> GlobalStateManagerResult<Option<OwnerTag>> {
self.release_subnet_v6(Ipv6Net::new(addr, 128).expect("must succeed")) self.release_subnet_v6(Ipv6Net::new(addr, 128).expect("must succeed"))
} }
pub fn release_subnet_v6(&mut self, net: Ipv6Net) -> MachineRegistryResult<Option<OwnerTag>> { pub fn release_subnet_v6(
&mut self,
net: Ipv6Net,
) -> GlobalStateManagerResult<Option<OwnerTag>> {
let mut address_pool = self.fields.address_pool.clone(); let mut address_pool = self.fields.address_pool.clone();
let opt_tag = address_pool.release_allocation_v6(net)?; let opt_tag = address_pool.release_allocation_v6(net)?;

View File

@ -4,6 +4,10 @@ use std::marker::PhantomData;
pub trait State: fmt::Debug + Clone { pub trait State: fmt::Debug + Clone {
fn id(&self) -> StateId<Self>; fn id(&self) -> StateId<Self>;
fn name(&self) -> Option<String>; fn name(&self) -> Option<String>;
fn debug_name(&self) -> String {
self.name()
.unwrap_or_else(|| format!("<{}>", self.id().external_id()))
}
} }
type StateIdInternal = u64; type StateIdInternal = u64;
@ -44,14 +48,14 @@ impl<S: State> core::hash::Hash for StateId<S> {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StateAllocator<S: State> { pub struct StateRegistry<S: State> {
state_id_by_name: imbl::HashMap<Arc<String>, StateIdInternal>, state_id_by_name: imbl::HashMap<Arc<String>, StateIdInternal>,
state_by_id: imbl::HashMap<StateIdInternal, Option<S>>, state_by_id: imbl::HashMap<StateIdInternal, Option<S>>,
next_state_id: StateIdInternal, next_state_id: StateIdInternal,
free_state_ids: imbl::Vector<StateIdInternal>, free_state_ids: imbl::Vector<StateIdInternal>,
} }
impl<S: State> StateAllocator<S> { impl<S: State> StateRegistry<S> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
state_id_by_name: imbl::HashMap::new(), state_id_by_name: imbl::HashMap::new(),
@ -90,10 +94,10 @@ impl<S: State> StateAllocator<S> {
StateId(state_id, PhantomData {}) StateId(state_id, PhantomData {})
} }
pub fn release_id(&mut self, id: StateId<S>) -> MachineRegistryResult<()> { pub fn release_id(&mut self, id: StateId<S>) -> GlobalStateManagerResult<()> {
// Remove id to state mapping // Remove id to state mapping
let Some(old_opt_state) = self.state_by_id.remove(&id.0) else { let Some(old_opt_state) = self.state_by_id.remove(&id.0) else {
return Err(MachineRegistryError::InvalidId); return Err(GlobalStateManagerError::InvalidId(id.external_id()));
}; };
// Release state if it is attached // Release state if it is attached
@ -112,24 +116,24 @@ impl<S: State> StateAllocator<S> {
Ok(()) Ok(())
} }
pub fn attach_state(&mut self, state: S) -> MachineRegistryResult<()> { pub fn attach_state(&mut self, state: S) -> GlobalStateManagerResult<()> {
// Get the id from the state // Get the id from the state
let id = state.id(); let id = state.id();
// Get the allocator slot // Get the allocator slot
let Some(opt_state) = self.state_by_id.get_mut(&id.0) else { let Some(opt_state) = self.state_by_id.get_mut(&id.0) else {
return Err(MachineRegistryError::InvalidId); return Err(GlobalStateManagerError::InvalidId(id.external_id()));
}; };
// Ensure the state slot isn't attached already // Ensure the state slot isn't attached already
if opt_state.is_some() { if opt_state.is_some() {
return Err(MachineRegistryError::AlreadyAttached); return Err(GlobalStateManagerError::AlreadyAttached);
} }
// Ensure the name isn't duplicated // Ensure the name isn't duplicated
if let Some(name) = state.name() { if let Some(name) = state.name() {
if self.state_id_by_name.contains_key(&name) { if self.state_id_by_name.contains_key(&name) {
return Err(MachineRegistryError::DuplicateName); return Err(GlobalStateManagerError::DuplicateName(name));
} }
// Register the named state // Register the named state
self.state_id_by_name self.state_id_by_name
@ -143,15 +147,15 @@ impl<S: State> StateAllocator<S> {
Ok(()) Ok(())
} }
pub fn detach_state(&mut self, id: StateId<S>) -> MachineRegistryResult<S> { pub fn detach_state(&mut self, id: StateId<S>) -> GlobalStateManagerResult<S> {
// Get the allocator slot // Get the allocator slot
let Some(opt_state) = self.state_by_id.get_mut(&id.0) else { let Some(opt_state) = self.state_by_id.get_mut(&id.0) else {
return Err(MachineRegistryError::InvalidId); return Err(GlobalStateManagerError::InvalidId(id.external_id()));
}; };
// Take the state out of the slot and ensure the state slot isn't detached already // Take the state out of the slot and ensure the state slot isn't detached already
let Some(state) = opt_state.take() else { let Some(state) = opt_state.take() else {
return Err(MachineRegistryError::NotAttached); return Err(GlobalStateManagerError::NotAttached);
}; };
// Release the name if it exists // Release the name if it exists
@ -166,13 +170,13 @@ impl<S: State> StateAllocator<S> {
Ok(state) Ok(state)
} }
pub fn get_state(&self, id: StateId<S>) -> MachineRegistryResult<S> { pub fn get_state(&self, id: StateId<S>) -> GlobalStateManagerResult<S> {
// Get the allocator slot // Get the allocator slot
let Some(opt_state) = self.state_by_id.get(&id.0) else { let Some(opt_state) = self.state_by_id.get(&id.0) else {
return Err(MachineRegistryError::InvalidId); return Err(GlobalStateManagerError::InvalidId(id.external_id()));
}; };
let Some(state) = opt_state else { let Some(state) = opt_state else {
return Err(MachineRegistryError::NotAttached); return Err(GlobalStateManagerError::NotAttached);
}; };
Ok(state.clone()) Ok(state.clone())
} }
@ -188,7 +192,7 @@ impl<S: State> StateAllocator<S> {
} }
} }
impl<S: State> Default for StateAllocator<S> { impl<S: State> Default for StateRegistry<S> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }

View File

@ -106,25 +106,25 @@ impl TemplateState {
}); });
} }
pub fn is_active(&self, machine_registry_inner: &mut MachineRegistryInner) -> bool { pub fn is_active(&self, gsm_inner: &mut GlobalStateManagerInner) -> bool {
// Save a backup of the entire state // Save a backup of the entire state
let backup = machine_registry_inner.clone(); let backup = gsm_inner.clone();
// Make a copy of this template state // Make a copy of this template state
let mut current_state = self.clone(); let mut current_state = self.clone();
// See what would happen if we try to generate this template // See what would happen if we try to generate this template
let ok = current_state.generate(machine_registry_inner).is_ok(); let ok = current_state.generate(gsm_inner).is_ok();
// Restore the backup // Restore the backup
*machine_registry_inner = backup; *gsm_inner = backup;
// Return if this worked or not // Return if this worked or not
ok ok
} }
/// Network filter that keeps this template generation within per-network limits /// Network filter that keeps this template generation within per-network limits
fn network_filter(&self, network_state_id: NetworkStateId) -> MachineRegistryResult<bool> { fn network_filter(&self, network_state_id: NetworkStateId) -> GlobalStateManagerResult<bool> {
// Get the per network info // Get the per network info
let Some(pni) = self.fields.machines_per_network.get(&network_state_id) else { let Some(pni) = self.fields.machines_per_network.get(&network_state_id) else {
// If we haven't allocated anything in the network yet it is // If we haven't allocated anything in the network yet it is
@ -144,26 +144,28 @@ impl TemplateState {
pub fn generate( pub fn generate(
&mut self, &mut self,
machine_registry_inner: &mut MachineRegistryInner, gsm_inner: &mut GlobalStateManagerInner,
) -> MachineRegistryResult<MachineStateId> { ) -> GlobalStateManagerResult<MachineStateId> {
// See if we have reached our machine limit // See if we have reached our machine limit
if let Some(limit_machine_count) = self.fields.limit_machine_count { if let Some(limit_machine_count) = self.fields.limit_machine_count {
if self.fields.machines.len() < limit_machine_count { if self.fields.machines.len() < limit_machine_count {
return Err(MachineRegistryError::TemplateComplete); return Err(GlobalStateManagerError::TemplateComplete(self.debug_name()));
} }
} }
// If existing networks are all full, we'd have to allocate one, see if we'd be able to do that // If existing networks are all full, we'd have to allocate one, see if we'd be able to do that
let Some(locations_list) = self.fields.locations_list.as_ref() else { let Some(locations_list) = self.fields.locations_list.as_ref() else {
return Err(MachineRegistryError::TemplateComplete); return Err(GlobalStateManagerError::TemplateComplete(self.debug_name()));
}; };
// Get a network to generate the machine on // Get a network to generate the machine on
let network_state = let Some(network_state) = locations_list.pick(gsm_inner, |_, x| self.network_filter(x))?
locations_list.pick(machine_registry_inner, |_, x| self.network_filter(x))?; else {
return Err(GlobalStateManagerError::TemplateComplete(self.debug_name()));
};
// Allocate a machine id // Allocate a machine id
let machine_state_id = machine_registry_inner.machine_states_mut().allocate_id(); let machine_state_id = gsm_inner.machine_states_mut().allocate_id();
// Create an anonymous machine state // Create an anonymous machine state
let mut machine_state = let mut machine_state =
@ -183,18 +185,18 @@ impl TemplateState {
// Make the default route interface // Make the default route interface
let vin0 = machine_state.allocate_interface(None, None)?; let vin0 = machine_state.allocate_interface(None, None)?;
machine_state.attach_network(machine_registry_inner, &vin0, network_state.id())?; machine_state.attach_network(gsm_inner, &vin0, network_state.id())?;
if network_state.is_ipv4() { if network_state.is_ipv4() {
machine_state.allocate_address_ipv4(machine_registry_inner, &vin0, None, None)?; machine_state.allocate_address_ipv4(gsm_inner, &vin0, None, None)?;
} }
if network_state.is_ipv6() { if network_state.is_ipv6() {
machine_state.allocate_address_ipv6(machine_registry_inner, &vin0, None, None)?; machine_state.allocate_address_ipv6(gsm_inner, &vin0, None, None)?;
} }
Ok(()) Ok(())
})() { })() {
// Release the machine state and id if things failed to allocate // Release the machine state and id if things failed to allocate
machine_state.release(machine_registry_inner); machine_state.release(gsm_inner);
machine_registry_inner gsm_inner
.machine_states_mut() .machine_states_mut()
.release_id(machine_state_id) .release_id(machine_state_id)
.expect("must succeed"); .expect("must succeed");
@ -202,7 +204,7 @@ impl TemplateState {
} }
// Attach the state to the id // Attach the state to the id
machine_registry_inner gsm_inner
.machine_states_mut() .machine_states_mut()
.attach_state(machine_state) .attach_state(machine_state)
.expect("must succeed"); .expect("must succeed");
@ -217,7 +219,7 @@ impl TemplateState {
.fields .fields
.limit_machines_per_network .limit_machines_per_network
.as_ref() .as_ref()
.map(|wl| *machine_registry_inner.srng().weighted_choice_ref(wl)); .map(|wl| *gsm_inner.srng().weighted_choice_ref(wl));
PerNetworkInfo { PerNetworkInfo {
limit_machine_count, limit_machine_count,
machines: imbl::HashSet::new(), machines: imbl::HashSet::new(),

View File

@ -1,87 +0,0 @@
mod address_pool;
mod machine_registry_inner;
mod state;
use super::*;
use address_pool::*;
use machine_registry_inner::*;
use state::*;
#[derive(Debug)]
struct Machine {}
#[derive(Debug)]
struct MachineRegistryUnlockedInner {
config: config::Config,
}
#[derive(Debug, Clone)]
pub enum MachineRegistryError {
InvalidId,
InvalidName,
InvalidPrefix,
AlreadyAttached,
NotAttached,
DuplicateName,
ProfileComplete,
TemplateComplete,
NetworkComplete,
BlueprintComplete,
ProfileNotFound,
MachineNotFound,
NetworkNotFound,
TemplateNotFound,
BlueprintNotFound,
ModelNotFound,
NoDefaultModel,
NoDefaultNetwork,
NoAllocation,
ResourceInUse,
}
pub type MachineRegistryResult<T> = Result<T, MachineRegistryError>;
#[derive(Debug, Clone)]
pub struct MachineRegistry {
inner: Arc<Mutex<MachineRegistryInner>>,
unlocked_inner: Arc<MachineRegistryUnlockedInner>,
}
impl MachineRegistry {
///////////////////////////////////////////////////////////
/// Public Interface
pub fn new(config: config::Config) -> Self {
let unlocked_inner = Arc::new(MachineRegistryUnlockedInner { config });
Self {
inner: Arc::new(Mutex::new(MachineRegistryInner::new(
unlocked_inner.clone(),
))),
unlocked_inner,
}
}
pub fn allocate(&self, profile: String) -> MachineRegistryResult<MachineId> {
let mut inner = self.inner.lock();
let saved_state = (*inner).clone();
match inner.allocate(profile) {
Ok(v) => Ok(v),
Err(e) => {
*inner = saved_state;
Err(e)
}
}
}
pub fn release(&self, machine_id: MachineId) -> MachineRegistryResult<()> {
let mut inner = self.inner.lock();
let saved_state = (*inner).clone();
match inner.release(machine_id) {
Ok(v) => Ok(v),
Err(e) => {
*inner = saved_state;
Err(e)
}
}
}
}

View File

@ -1,12 +1,12 @@
pub mod config; pub mod config;
mod machine_registry; mod global_state_manager;
mod server_processor; mod server_processor;
mod stable_rng; mod stable_rng;
mod weighted_list; mod weighted_list;
use super::*; use super::*;
use machine_registry::*; use global_state_manager::*;
use server_processor::*; use server_processor::*;
use stable_rng::*; use stable_rng::*;
use weighted_list::*; use weighted_list::*;
@ -26,6 +26,8 @@ pub enum RouterServerError {
SerializationError(postcard::Error), SerializationError(postcard::Error),
#[error("IO Error: {0}")] #[error("IO Error: {0}")]
IoError(io::ErrorKind), IoError(io::ErrorKind),
#[error("State Error: {0}")]
StateError(global_state_manager::GlobalStateManagerError),
} }
pub type RouterServerResult<T> = Result<T, RouterServerError>; pub type RouterServerResult<T> = Result<T, RouterServerError>;
@ -40,10 +42,10 @@ enum RunLoopEvent {
#[derive(Debug)] #[derive(Debug)]
struct RouterServerUnlockedInner { struct RouterServerUnlockedInner {
config: config::Config,
new_client_sender: flume::Sender<SendPinBoxFuture<RunLoopEvent>>, new_client_sender: flume::Sender<SendPinBoxFuture<RunLoopEvent>>,
new_client_receiver: flume::Receiver<SendPinBoxFuture<RunLoopEvent>>, new_client_receiver: flume::Receiver<SendPinBoxFuture<RunLoopEvent>>,
server_processor: ServerProcessor, server_processor: ServerProcessor,
global_state_manager: GlobalStateManager,
} }
#[derive(Debug)] #[derive(Debug)]
@ -60,69 +62,44 @@ pub struct RouterServer {
inner: Arc<Mutex<RouterServerInner>>, inner: Arc<Mutex<RouterServerInner>>,
} }
impl Default for RouterServer {
fn default() -> Self {
Self::new()
}
}
impl RouterServer { impl RouterServer {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Public Interface // Public Interface
/// Create a router server for virtual networking /// Create a router server for virtual networking
pub fn new(config: config::Config) -> Self { pub fn new() -> Self {
// Make a channel to receive new clients // Make a channel to receive new clients
let (new_client_sender, new_client_receiver) = flume::unbounded(); let (new_client_sender, new_client_receiver) = flume::unbounded();
// Make a machine registry to manage state
let global_state_manager = GlobalStateManager::new();
// Make a server processor to handle messages // Make a server processor to handle messages
let server_processor = ServerProcessor::new(config.clone()); let server_processor = ServerProcessor::new(global_state_manager.clone());
Self { Self {
unlocked_inner: Arc::new(RouterServerUnlockedInner { unlocked_inner: Arc::new(RouterServerUnlockedInner {
config,
new_client_sender, new_client_sender,
new_client_receiver, new_client_receiver,
server_processor, server_processor,
global_state_manager,
}), }),
inner: Arc::new(Mutex::new(RouterServerInner {})), inner: Arc::new(Mutex::new(RouterServerInner {})),
} }
} }
async fn process_connection<R, W>(self, reader: R, writer: W) -> RunLoopEvent /// Execute a config file on the global state manager
where pub fn execute_config(&self, cfg: config::Config) -> RouterServerResult<()> {
R: AsyncRead + Send + Unpin,
W: AsyncWrite + Send + Unpin,
{
let framed_reader = FramedRead::new(reader, BytesCodec);
let framed_writer = FramedWrite::new(writer, BytesCodec);
let (outbound_sender, outbound_receiver) = flume::unbounded();
let outbound_fut = system_boxed(
outbound_receiver
.into_stream()
.map(|command| {
to_stdvec(&command)
.map_err(io::Error::other)
.map(Bytes::from)
})
.forward(framed_writer),
);
let inbound_fut = system_boxed(framed_reader.try_for_each(|x| async {
let x = x;
let cmd = from_bytes::<ServerProcessorCommand>(&x).map_err(io::Error::other)?;
self.unlocked_inner self.unlocked_inner
.server_processor .global_state_manager
.enqueue_command(cmd, outbound_sender.clone()); .execute_config(cfg)
.map_err(RouterServerError::StateError)
Ok(())
}));
let mut unord = FuturesUnordered::new();
unord.push(outbound_fut);
unord.push(inbound_fut);
if let Some(Err(e)) = unord.next().await {
error!("{}", e);
}
RunLoopEvent::Done
} }
/// Accept RouterClient connections on a TCP socket /// Accept RouterClient connections on a TCP socket
@ -329,4 +306,46 @@ impl RouterServer {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Private Implementation // Private Implementation
async fn process_connection<R, W>(self, reader: R, writer: W) -> RunLoopEvent
where
R: AsyncRead + Send + Unpin,
W: AsyncWrite + Send + Unpin,
{
let framed_reader = FramedRead::new(reader, BytesCodec);
let framed_writer = FramedWrite::new(writer, BytesCodec);
let (outbound_sender, outbound_receiver) = flume::unbounded();
let outbound_fut = system_boxed(
outbound_receiver
.into_stream()
.map(|command| {
to_stdvec(&command)
.map_err(io::Error::other)
.map(Bytes::from)
})
.forward(framed_writer),
);
let inbound_fut = system_boxed(framed_reader.try_for_each(|x| async {
let x = x;
let cmd = from_bytes::<ServerProcessorCommand>(&x).map_err(io::Error::other)?;
self.unlocked_inner
.server_processor
.enqueue_command(cmd, outbound_sender.clone());
Ok(())
}));
let mut unord = FuturesUnordered::new();
unord.push(outbound_fut);
unord.push(inbound_fut);
if let Some(Err(e)) = unord.next().await {
error!("{}", e);
}
RunLoopEvent::Done
}
} }

View File

@ -12,11 +12,9 @@ struct ServerProcessorInner {
#[derive(Debug)] #[derive(Debug)]
struct ServerProcessorUnlockedInner { struct ServerProcessorUnlockedInner {
config: config::Config, machine_registry: GlobalStateManager,
receiver: flume::Receiver<ServerProcessorCommandRecord>, receiver: flume::Receiver<ServerProcessorCommandRecord>,
sender: flume::Sender<ServerProcessorCommandRecord>, sender: flume::Sender<ServerProcessorCommandRecord>,
machine_registry: MachineRegistry,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -29,15 +27,14 @@ impl ServerProcessor {
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Public Interface // Public Interface
pub fn new(config: config::Config) -> Self { pub fn new(machine_registry: GlobalStateManager) -> Self {
let (sender, receiver) = flume::unbounded(); let (sender, receiver) = flume::unbounded();
Self { Self {
unlocked_inner: Arc::new(ServerProcessorUnlockedInner { unlocked_inner: Arc::new(ServerProcessorUnlockedInner {
config: config.clone(),
sender, sender,
receiver, receiver,
machine_registry: MachineRegistry::new(config), machine_registry,
}), }),
inner: Arc::new(Mutex::new(ServerProcessorInner {})), inner: Arc::new(Mutex::new(ServerProcessorInner {})),
} }