mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-01-11 23:39:36 -05:00
[skip ci] refactor and make multiple configs possible
This commit is contained in:
parent
9e7c41b635
commit
d83f09d058
@ -78,7 +78,11 @@ fn main() -> Result<(), String> {
|
||||
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 {
|
||||
Some(
|
||||
|
@ -58,9 +58,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn can_allocate_v6(&self, prefix: u8) -> MachineRegistryResult<bool> {
|
||||
pub fn can_allocate_v6(&self, prefix: u8) -> GlobalStateManagerResult<bool> {
|
||||
if prefix > 128 {
|
||||
return Err(MachineRegistryError::InvalidPrefix);
|
||||
return Err(GlobalStateManagerError::InvalidPrefix(prefix));
|
||||
}
|
||||
|
||||
let mut srng = StableRng::new(0);
|
||||
@ -68,9 +68,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
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 {
|
||||
return Err(MachineRegistryError::InvalidPrefix);
|
||||
return Err(GlobalStateManagerError::InvalidPrefix(prefix));
|
||||
}
|
||||
|
||||
let mut srng = StableRng::new(0);
|
||||
@ -82,15 +82,15 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
&mut self,
|
||||
allocation: Ipv4Net,
|
||||
opt_tag: Option<T>,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
// Ensure the allocation is in our scope
|
||||
if !self.is_in_scope_v4(allocation) {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
}
|
||||
|
||||
// Only reserve if it's not overlapping an allocation
|
||||
if !self.get_overlaps_v4(allocation).is_empty() {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
}
|
||||
|
||||
// Add to our allocated pool
|
||||
@ -104,15 +104,15 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
&mut self,
|
||||
allocation: Ipv6Net,
|
||||
opt_tag: Option<T>,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
// Ensure the allocation is in our scope
|
||||
if !self.is_in_scope_v6(allocation) {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
}
|
||||
|
||||
// Only reserve if it's not overlapping an allocation
|
||||
if !self.get_overlaps_v6(allocation).is_empty() {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
}
|
||||
|
||||
// Add to our allocated pool
|
||||
@ -149,9 +149,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
srng: &mut StableRng,
|
||||
prefix: u8,
|
||||
tag: T,
|
||||
) -> MachineRegistryResult<Option<Ipv4Net>> {
|
||||
) -> GlobalStateManagerResult<Option<Ipv4Net>> {
|
||||
if prefix > 32 {
|
||||
return Err(MachineRegistryError::InvalidPrefix);
|
||||
return Err(GlobalStateManagerError::InvalidPrefix(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,
|
||||
prefix: u8,
|
||||
tag: T,
|
||||
) -> MachineRegistryResult<Option<Ipv6Net>> {
|
||||
) -> GlobalStateManagerResult<Option<Ipv6Net>> {
|
||||
if prefix > 128 {
|
||||
return Err(MachineRegistryError::InvalidPrefix);
|
||||
return Err(GlobalStateManagerError::InvalidPrefix(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(
|
||||
&mut self,
|
||||
allocation: Ipv4Net,
|
||||
) -> MachineRegistryResult<Option<T>> {
|
||||
) -> GlobalStateManagerResult<Option<T>> {
|
||||
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 {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
};
|
||||
|
||||
self.allocated_v4.remove(pos);
|
||||
@ -212,13 +212,13 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
pub fn release_allocation_v6(
|
||||
&mut self,
|
||||
allocation: Ipv6Net,
|
||||
) -> MachineRegistryResult<Option<T>> {
|
||||
) -> GlobalStateManagerResult<Option<T>> {
|
||||
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 {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
};
|
||||
|
||||
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>(
|
||||
&mut self,
|
||||
mut check: F,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
if !self.is_ipv4() {
|
||||
return Ok(());
|
||||
}
|
||||
@ -272,7 +272,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
IpNet::V4(ipv4_net) => check(ipv4_net, t),
|
||||
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");
|
||||
self.scope_v4.clear();
|
||||
@ -284,7 +286,7 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
pub fn clear_ipv6<F: FnMut(Ipv6Net, &T) -> bool>(
|
||||
&mut self,
|
||||
mut check: F,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
if !self.is_ipv6() {
|
||||
return Ok(());
|
||||
}
|
||||
@ -292,7 +294,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
|
||||
IpNet::V4(_ipv4_net) => false,
|
||||
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");
|
||||
self.scope_v6.clear();
|
@ -1,73 +1,86 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) struct MachineRegistryInner {
|
||||
unlocked_inner: Arc<MachineRegistryUnlockedInner>,
|
||||
pub(super) struct GlobalStateManagerInner {
|
||||
unlocked_inner: Arc<GlobalStateManagerUnlockedInner>,
|
||||
srng: StableRng,
|
||||
models: imbl::HashMap<String, config::Model>,
|
||||
allocations: imbl::HashMap<String, config::Allocation>,
|
||||
allocated_machines: imbl::HashSet<MachineStateId>,
|
||||
profile_state_allocator: StateAllocator<ProfileState>,
|
||||
machine_state_allocator: StateAllocator<MachineState>,
|
||||
template_state_allocator: StateAllocator<TemplateState>,
|
||||
network_state_allocator: StateAllocator<NetworkState>,
|
||||
blueprint_state_allocator: StateAllocator<BlueprintState>,
|
||||
profile_state_registry: StateRegistry<ProfileState>,
|
||||
machine_state_registry: StateRegistry<MachineState>,
|
||||
template_state_registry: StateRegistry<TemplateState>,
|
||||
network_state_registry: StateRegistry<NetworkState>,
|
||||
blueprint_state_registry: StateRegistry<BlueprintState>,
|
||||
}
|
||||
|
||||
impl MachineRegistryInner {
|
||||
impl GlobalStateManagerInner {
|
||||
///////////////////////////////////////////////////////////
|
||||
/// Public Interface
|
||||
|
||||
pub fn new(unlocked_inner: Arc<MachineRegistryUnlockedInner>) -> Self {
|
||||
let srng = StableRng::new(unlocked_inner.config.seed.unwrap_or_default());
|
||||
|
||||
MachineRegistryInner {
|
||||
pub fn new(unlocked_inner: Arc<GlobalStateManagerUnlockedInner>) -> Self {
|
||||
GlobalStateManagerInner {
|
||||
unlocked_inner,
|
||||
srng,
|
||||
srng: StableRng::new(0),
|
||||
models: imbl::HashMap::new(),
|
||||
allocations: imbl::HashMap::new(),
|
||||
allocated_machines: imbl::HashSet::new(),
|
||||
profile_state_allocator: StateAllocator::new(),
|
||||
machine_state_allocator: StateAllocator::new(),
|
||||
template_state_allocator: StateAllocator::new(),
|
||||
network_state_allocator: StateAllocator::new(),
|
||||
blueprint_state_allocator: StateAllocator::new(),
|
||||
profile_state_registry: StateRegistry::new(),
|
||||
machine_state_registry: StateRegistry::new(),
|
||||
template_state_registry: StateRegistry::new(),
|
||||
network_state_registry: StateRegistry::new(),
|
||||
blueprint_state_registry: StateRegistry::new(),
|
||||
}
|
||||
}
|
||||
pub fn srng(&mut self) -> &mut StableRng {
|
||||
&mut self.srng
|
||||
}
|
||||
pub fn config(&self) -> &config::Config {
|
||||
&self.unlocked_inner.config
|
||||
}
|
||||
|
||||
pub fn execute_config(&self, cfg: config::Config) -> MachineRegistryResult<()> {
|
||||
// Create all networks
|
||||
pub fn execute_config(&mut self, cfg: config::Config) -> GlobalStateManagerResult<()> {
|
||||
// Create random number generator
|
||||
if let Some(seed) = cfg.seed {
|
||||
self.srng = StableRng::new(seed);
|
||||
}
|
||||
|
||||
// Create all blueprints
|
||||
// Import all allocation definitions
|
||||
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 templates
|
||||
// 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 machines
|
||||
// Create all profile states
|
||||
|
||||
// Create all network states
|
||||
|
||||
// Create all blueprint states
|
||||
|
||||
// Create all template states
|
||||
|
||||
// Create all machine states
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn allocate(&mut self, profile: String) -> MachineRegistryResult<MachineId> {
|
||||
// Get profile definition
|
||||
let Some(profile_def) = self.unlocked_inner.config.profiles.get(&profile) else {
|
||||
return Err(MachineRegistryError::ProfileNotFound);
|
||||
pub fn allocate(&mut self, profile: String) -> GlobalStateManagerResult<MachineId> {
|
||||
// Get current profile state
|
||||
let Some(profile_state_id) = self.profile_state_registry.get_state_id_by_name(&profile)
|
||||
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
|
||||
loop {
|
||||
// Move to the next profile instance
|
||||
let mut profile_state = self.profile_states().get_state(profile_state_id)?;
|
||||
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);
|
||||
|
||||
@ -80,7 +93,7 @@ impl MachineRegistryInner {
|
||||
let Some(machine_state_id) =
|
||||
self.machine_states().get_state_id_by_name(name)
|
||||
else {
|
||||
return Err(MachineRegistryError::MachineNotFound);
|
||||
return Err(GlobalStateManagerError::MachineNotFound(name.clone()));
|
||||
};
|
||||
if self.allocated_machines.contains(&machine_state_id) {
|
||||
Ok(None)
|
||||
@ -109,7 +122,7 @@ impl MachineRegistryInner {
|
||||
let Some(template_state_id) =
|
||||
self.template_states().get_state_id_by_name(name)
|
||||
else {
|
||||
return Err(MachineRegistryError::TemplateNotFound);
|
||||
return Err(GlobalStateManagerError::TemplateNotFound(name.clone()));
|
||||
};
|
||||
let template_state = self
|
||||
.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);
|
||||
if self.allocated_machines.contains(&id) {
|
||||
// Was a fixed machine, so we leave the machine state so it can
|
||||
@ -162,36 +175,47 @@ impl MachineRegistryInner {
|
||||
///////////////////////////////////////////////////////////
|
||||
/// Private Implementation
|
||||
|
||||
pub(super) fn profile_states(&self) -> &StateAllocator<ProfileState> {
|
||||
&self.profile_state_allocator
|
||||
}
|
||||
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 srng(&mut self) -> &mut StableRng {
|
||||
&mut self.srng
|
||||
}
|
||||
|
||||
pub(super) fn profile_states_mut(&mut self) -> &mut StateAllocator<ProfileState> {
|
||||
&mut self.profile_state_allocator
|
||||
pub(super) fn models(&self) -> &imbl::HashMap<String, config::Model> {
|
||||
&self.models
|
||||
}
|
||||
pub(super) fn machine_states_mut(&mut self) -> &mut StateAllocator<MachineState> {
|
||||
&mut self.machine_state_allocator
|
||||
pub(super) fn allocations(&self) -> &imbl::HashMap<String, config::Allocation> {
|
||||
&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> {
|
||||
&mut self.network_state_allocator
|
||||
pub(super) fn machine_states(&self) -> &StateRegistry<MachineState> {
|
||||
&self.machine_state_registry
|
||||
}
|
||||
pub(super) fn blueprint_states_mut(&mut self) -> &mut StateAllocator<BlueprintState> {
|
||||
&mut self.blueprint_state_allocator
|
||||
pub(super) fn template_states(&self) -> &StateRegistry<TemplateState> {
|
||||
&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(
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -69,7 +69,7 @@ pub struct BlueprintState {
|
||||
pub type BlueprintStateId = StateId<BlueprintState>;
|
||||
|
||||
impl BlueprintState {
|
||||
pub fn new(id: BlueprintStateId, name: String) -> MachineRegistryResult<BlueprintState> {
|
||||
pub fn new(id: BlueprintStateId, name: String) -> GlobalStateManagerResult<BlueprintState> {
|
||||
Ok(Self {
|
||||
immutable: Arc::new(BlueprintStateImmutable { id, name }),
|
||||
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
|
||||
let backup = machine_registry_inner.clone();
|
||||
let backup = gsm_inner.clone();
|
||||
|
||||
// Make a copy of this blueprint state
|
||||
let mut current_state = self.clone();
|
||||
|
||||
// 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
|
||||
*machine_registry_inner = backup;
|
||||
*gsm_inner = backup;
|
||||
|
||||
// Return if this worked or not
|
||||
ok
|
||||
@ -184,20 +184,16 @@ impl BlueprintState {
|
||||
|
||||
fn generate_model_inner(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
network_state: &mut NetworkState,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let model_name = match self.fields.model.as_ref() {
|
||||
Some(models) => (**machine_registry_inner.srng().weighted_choice_ref(models)).clone(),
|
||||
None => machine_registry_inner
|
||||
.config()
|
||||
.default_model
|
||||
.as_ref()
|
||||
.ok_or(MachineRegistryError::NoDefaultModel)?
|
||||
.clone(),
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let Some(model_list) = self.fields.model.as_ref() else {
|
||||
return Err(GlobalStateManagerError::NoDefaultModel);
|
||||
};
|
||||
let Some(model) = machine_registry_inner.config().models.get(&model_name) else {
|
||||
return Err(MachineRegistryError::ModelNotFound);
|
||||
let model_name = (**gsm_inner.srng().weighted_choice_ref(model_list)).clone();
|
||||
|
||||
let Some(model) = gsm_inner.models().get(&model_name) else {
|
||||
return Err(GlobalStateManagerError::ModelNotFound(model_name));
|
||||
};
|
||||
|
||||
let params = NetworkStateModelParams {
|
||||
@ -212,13 +208,11 @@ impl BlueprintState {
|
||||
/// Network filter that ensures we can allocate an ipv4 gateway address on a network
|
||||
fn gateway_network_filter_v4(
|
||||
&self,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
gsm_inner: &GlobalStateManagerInner,
|
||||
network_state_id: NetworkStateId,
|
||||
) -> MachineRegistryResult<bool> {
|
||||
) -> GlobalStateManagerResult<bool> {
|
||||
// Get the network state
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(network_state_id)?;
|
||||
let network_state = gsm_inner.network_states().get_state(network_state_id)?;
|
||||
|
||||
// See if we can allocate on this network
|
||||
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
|
||||
fn gateway_network_filter_v6(
|
||||
&self,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
gsm_inner: &GlobalStateManagerInner,
|
||||
network_state_id: NetworkStateId,
|
||||
) -> MachineRegistryResult<bool> {
|
||||
) -> GlobalStateManagerResult<bool> {
|
||||
// Get the network state
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(network_state_id)?;
|
||||
let network_state = gsm_inner.network_states().get_state(network_state_id)?;
|
||||
|
||||
// See if we can allocate on this network
|
||||
let can_allocate = network_state.can_allocate_address_v6(None);
|
||||
@ -245,19 +237,24 @@ impl BlueprintState {
|
||||
|
||||
fn generate_ipv4_inner(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
network_state: &mut NetworkState,
|
||||
) -> MachineRegistryResult<()> {
|
||||
network_state.clear_ipv4(machine_registry_inner)?;
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
network_state.clear_ipv4(gsm_inner)?;
|
||||
let Some(ipv4) = self.fields.ipv4.as_ref() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Get addresses for network
|
||||
let NetworkLocation { subnet, super_net } = ipv4
|
||||
let Some(NetworkLocation { subnet, super_net }) = ipv4
|
||||
.params
|
||||
.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 {
|
||||
allocation: subnet,
|
||||
@ -266,35 +263,37 @@ impl BlueprintState {
|
||||
|
||||
let gateway_params = match ipv4.gateway.as_ref() {
|
||||
Some(v4gw) => {
|
||||
let translation = *machine_registry_inner
|
||||
let translation = *gsm_inner
|
||||
.srng()
|
||||
.weighted_choice_ref(&v4gw.params.translation);
|
||||
let upnp = machine_registry_inner
|
||||
.srng()
|
||||
.probability_test(v4gw.params.upnp);
|
||||
let upnp = gsm_inner.srng().probability_test(v4gw.params.upnp);
|
||||
|
||||
let (external_network, external_address) = match v4gw.params.locations.as_ref() {
|
||||
Some(locations_list) => {
|
||||
// A external network location was specified, pick one
|
||||
// Get a network to generate the machine on
|
||||
let mut gateway_network_state = locations_list.pick(
|
||||
machine_registry_inner,
|
||||
|machine_registry_inner, id| {
|
||||
self.gateway_network_filter_v4(machine_registry_inner, id)
|
||||
},
|
||||
)?;
|
||||
let Some(mut gateway_network_state) = locations_list
|
||||
.pick(gsm_inner, |gsm_inner, id| {
|
||||
self.gateway_network_filter_v4(gsm_inner, id)
|
||||
})?
|
||||
else {
|
||||
return Err(GlobalStateManagerError::BlueprintComplete(
|
||||
self.debug_name(),
|
||||
));
|
||||
};
|
||||
|
||||
let gateway_network_state_id = gateway_network_state.id();
|
||||
|
||||
// Allocate an external address on this network
|
||||
let external_interface_address = gateway_network_state
|
||||
.allocate_address_v4(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Gateway(network_state.id()),
|
||||
None,
|
||||
)?;
|
||||
|
||||
// Update the network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(gateway_network_state);
|
||||
|
||||
@ -321,25 +320,30 @@ impl BlueprintState {
|
||||
None => None,
|
||||
};
|
||||
|
||||
network_state.set_ipv4(machine_registry_inner, params, gateway_params)?;
|
||||
network_state.set_ipv4(gsm_inner, params, gateway_params)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_ipv6_inner(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
network_state: &mut NetworkState,
|
||||
) -> MachineRegistryResult<()> {
|
||||
network_state.clear_ipv6(machine_registry_inner)?;
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
network_state.clear_ipv6(gsm_inner)?;
|
||||
let Some(ipv6) = self.fields.ipv6.as_ref() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Get addresses for network
|
||||
let NetworkLocation { subnet, super_net } = ipv6
|
||||
let Some(NetworkLocation { subnet, super_net }) = ipv6
|
||||
.params
|
||||
.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 {
|
||||
allocation: subnet,
|
||||
@ -348,35 +352,37 @@ impl BlueprintState {
|
||||
|
||||
let gateway_params = match ipv6.gateway.as_ref() {
|
||||
Some(v6gw) => {
|
||||
let translation = *machine_registry_inner
|
||||
let translation = *gsm_inner
|
||||
.srng()
|
||||
.weighted_choice_ref(&v6gw.params.translation);
|
||||
let upnp = machine_registry_inner
|
||||
.srng()
|
||||
.probability_test(v6gw.params.upnp);
|
||||
let upnp = gsm_inner.srng().probability_test(v6gw.params.upnp);
|
||||
|
||||
let (external_network, external_address) = match v6gw.params.locations.as_ref() {
|
||||
Some(locations_list) => {
|
||||
// A external network location was specified, pick one
|
||||
// Get a network to generate the machine on
|
||||
let mut gateway_network_state = locations_list.pick(
|
||||
machine_registry_inner,
|
||||
|machine_registry_inner, id| {
|
||||
self.gateway_network_filter_v6(machine_registry_inner, id)
|
||||
},
|
||||
)?;
|
||||
let Some(mut gateway_network_state) = locations_list
|
||||
.pick(gsm_inner, |gsm_inner, id| {
|
||||
self.gateway_network_filter_v6(gsm_inner, id)
|
||||
})?
|
||||
else {
|
||||
return Err(GlobalStateManagerError::BlueprintComplete(
|
||||
self.debug_name(),
|
||||
));
|
||||
};
|
||||
|
||||
let gateway_network_state_id = gateway_network_state.id();
|
||||
|
||||
// Allocate an external address on this network
|
||||
let external_interface_address = gateway_network_state
|
||||
.allocate_address_v6(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Gateway(network_state.id()),
|
||||
None,
|
||||
)?;
|
||||
|
||||
// Update the network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(gateway_network_state);
|
||||
|
||||
@ -403,37 +409,39 @@ impl BlueprintState {
|
||||
None => None,
|
||||
};
|
||||
|
||||
network_state.set_ipv6(machine_registry_inner, params, gateway_params)?;
|
||||
network_state.set_ipv6(gsm_inner, params, gateway_params)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<NetworkStateId> {
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
) -> GlobalStateManagerResult<NetworkStateId> {
|
||||
// See if there's room for another network
|
||||
if let Some(limit_network_count) = self.fields.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
|
||||
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
|
||||
let mut network_state =
|
||||
NetworkState::new(network_state_id, None, NetworkOrigin::Blueprint(self.id()));
|
||||
|
||||
if let Err(e) = (|| {
|
||||
self.generate_model_inner(machine_registry_inner, &mut network_state)?;
|
||||
self.generate_ipv4_inner(machine_registry_inner, &mut network_state)?;
|
||||
self.generate_ipv6_inner(machine_registry_inner, &mut network_state)?;
|
||||
self.generate_model_inner(gsm_inner, &mut network_state)?;
|
||||
self.generate_ipv4_inner(gsm_inner, &mut network_state)?;
|
||||
self.generate_ipv6_inner(gsm_inner, &mut network_state)?;
|
||||
Ok(())
|
||||
})() {
|
||||
// Release the network state and id if things failed to allocate
|
||||
network_state.release(machine_registry_inner);
|
||||
machine_registry_inner
|
||||
network_state.release(gsm_inner);
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.release_id(network_state_id)
|
||||
.expect("must succeed");
|
||||
@ -441,9 +449,7 @@ impl BlueprintState {
|
||||
}
|
||||
|
||||
// Attach the state to the id
|
||||
machine_registry_inner
|
||||
.network_states_mut()
|
||||
.attach_state(network_state)?;
|
||||
gsm_inner.network_states_mut().attach_state(network_state)?;
|
||||
|
||||
// Record the newly instantiated network
|
||||
let mut networks = self.fields.networks.clone();
|
||||
@ -458,9 +464,9 @@ impl BlueprintState {
|
||||
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
|
||||
F: FnMut(NetworkStateId) -> MachineRegistryResult<Option<R>>,
|
||||
F: FnMut(NetworkStateId) -> GlobalStateManagerResult<Option<R>>,
|
||||
{
|
||||
for network_id in &self.fields.networks {
|
||||
if let Some(res) = callback(*network_id)? {
|
@ -20,24 +20,19 @@ pub enum MachineLocationsList {
|
||||
impl MachineLocationsList {
|
||||
pub fn can_pick<F>(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
mut network_filter: F,
|
||||
) -> MachineRegistryResult<bool>
|
||||
) -> GlobalStateManagerResult<bool>
|
||||
where
|
||||
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>,
|
||||
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
|
||||
{
|
||||
match self {
|
||||
MachineLocationsList::Networks { networks } => {
|
||||
// Filter the weighted list of networks to those that are still active and or not yet started
|
||||
if networks
|
||||
.try_filter(|id| {
|
||||
let network_state =
|
||||
machine_registry_inner.network_states().get_state(*id)?;
|
||||
self.is_network_available(
|
||||
machine_registry_inner,
|
||||
network_state,
|
||||
&mut network_filter,
|
||||
)
|
||||
let network_state = gsm_inner.network_states().get_state(*id)?;
|
||||
self.is_network_available(gsm_inner, network_state, &mut network_filter)
|
||||
})?
|
||||
.is_none()
|
||||
{
|
||||
@ -48,15 +43,10 @@ impl MachineLocationsList {
|
||||
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
||||
if blueprints
|
||||
.try_filter(|id| {
|
||||
let blueprint_state =
|
||||
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||
let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?;
|
||||
|
||||
self.is_blueprint_available(
|
||||
machine_registry_inner,
|
||||
blueprint_state,
|
||||
&mut network_filter,
|
||||
)
|
||||
.map(|x| x.is_some())
|
||||
self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter)
|
||||
.map(|x| x.is_some())
|
||||
})?
|
||||
.is_none()
|
||||
{
|
||||
@ -69,20 +59,20 @@ impl MachineLocationsList {
|
||||
|
||||
pub fn pick<F>(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
mut network_filter: F,
|
||||
) -> MachineRegistryResult<NetworkState>
|
||||
) -> GlobalStateManagerResult<Option<NetworkState>>
|
||||
where
|
||||
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>,
|
||||
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
|
||||
{
|
||||
// Get a network to generate the machine on
|
||||
let network_state = match self {
|
||||
MachineLocationsList::Networks { networks } => {
|
||||
// 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 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(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
network_state.clone(),
|
||||
&mut network_filter,
|
||||
)? {
|
||||
@ -92,13 +82,11 @@ impl MachineLocationsList {
|
||||
}
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::NetworkComplete);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Weighted choice of network now that we have a candidate list
|
||||
let network_state = machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice(available_networks);
|
||||
let network_state = gsm_inner.srng().weighted_choice(available_networks);
|
||||
|
||||
// Return network state to use
|
||||
network_state
|
||||
@ -106,54 +94,42 @@ impl MachineLocationsList {
|
||||
MachineLocationsList::Blueprints { blueprints } => {
|
||||
// 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 blueprint_state =
|
||||
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||
let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?;
|
||||
|
||||
self.is_blueprint_available(
|
||||
machine_registry_inner,
|
||||
blueprint_state,
|
||||
&mut network_filter,
|
||||
)
|
||||
self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter)
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::BlueprintComplete);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Weighted choice of blueprint now that we have a candidate list
|
||||
match machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice(available_blueprints)
|
||||
{
|
||||
match gsm_inner.srng().weighted_choice(available_blueprints) {
|
||||
BlueprintAvailability::Existing(network_state) => network_state,
|
||||
BlueprintAvailability::Generate(mut 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
|
||||
machine_registry_inner
|
||||
.blueprint_states_mut()
|
||||
.set_state(blueprint_state);
|
||||
gsm_inner.blueprint_states_mut().set_state(blueprint_state);
|
||||
|
||||
// Return network state
|
||||
machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(network_state_id)?
|
||||
gsm_inner.network_states().get_state(network_state_id)?
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(network_state)
|
||||
Ok(Some(network_state))
|
||||
}
|
||||
|
||||
fn is_network_available<F>(
|
||||
&self,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
gsm_inner: &GlobalStateManagerInner,
|
||||
network_state: NetworkState,
|
||||
mut network_filter: F,
|
||||
) -> MachineRegistryResult<bool>
|
||||
) -> GlobalStateManagerResult<bool>
|
||||
where
|
||||
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>,
|
||||
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
|
||||
{
|
||||
// If the network is not active, it is not available
|
||||
if !network_state.is_active()? {
|
||||
@ -161,7 +137,7 @@ impl MachineLocationsList {
|
||||
}
|
||||
|
||||
// Check the network filter
|
||||
if !network_filter(machine_registry_inner, network_state.id())? {
|
||||
if !network_filter(gsm_inner, network_state.id())? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
@ -170,23 +146,19 @@ impl MachineLocationsList {
|
||||
|
||||
fn is_blueprint_available<F>(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
blueprint_state: BlueprintState,
|
||||
mut network_filter: F,
|
||||
) -> MachineRegistryResult<Option<BlueprintAvailability>>
|
||||
) -> GlobalStateManagerResult<Option<BlueprintAvailability>>
|
||||
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
|
||||
// in this template
|
||||
if let Some(available_network_state) = blueprint_state.for_each_network_id(|id| {
|
||||
// Check the network's availability
|
||||
let network_state = machine_registry_inner.network_states().get_state(id)?;
|
||||
if self.is_network_available(
|
||||
machine_registry_inner,
|
||||
network_state.clone(),
|
||||
&mut network_filter,
|
||||
)? {
|
||||
let network_state = gsm_inner.network_states().get_state(id)?;
|
||||
if self.is_network_available(gsm_inner, network_state.clone(), &mut network_filter)? {
|
||||
// We found one
|
||||
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 blueprint_state.is_active(machine_registry_inner) {
|
||||
if blueprint_state.is_active(gsm_inner) {
|
||||
return Ok(Some(BlueprintAvailability::Generate(blueprint_state)));
|
||||
}
|
||||
|
@ -60,17 +60,17 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release(mut self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||
self.release_all_interfaces(machine_registry_inner)
|
||||
pub fn release(mut self, gsm_inner: &mut GlobalStateManagerInner) {
|
||||
self.release_all_interfaces(gsm_inner)
|
||||
.expect("must succeed");
|
||||
|
||||
if let MachineOrigin::Template(generating_template) = self.immutable.origin {
|
||||
let mut template_state = machine_registry_inner
|
||||
let mut template_state = gsm_inner
|
||||
.template_states()
|
||||
.get_state(generating_template)
|
||||
.expect("must exist");
|
||||
template_state.on_machine_released(self.id());
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.template_states_mut()
|
||||
.set_state(template_state);
|
||||
}
|
||||
@ -105,12 +105,14 @@ impl MachineState {
|
||||
&mut self,
|
||||
interface_name: Option<String>,
|
||||
opt_interface_flags: Option<InterfaceFlags>,
|
||||
) -> MachineRegistryResult<Arc<String>> {
|
||||
) -> GlobalStateManagerResult<Arc<String>> {
|
||||
let interface_key = interface_name
|
||||
.map(Arc::new)
|
||||
.unwrap_or_else(|| self.next_free_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 {
|
||||
is_loopback: false,
|
||||
@ -146,35 +148,39 @@ impl MachineState {
|
||||
|
||||
pub fn allocate_address_ipv4(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
interface_name: &str,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
opt_address_flags: Option<AddressFlags>,
|
||||
) -> MachineRegistryResult<Ifv4Addr> {
|
||||
) -> GlobalStateManagerResult<Ifv4Addr> {
|
||||
let interface_key = Arc::new(interface_name.to_string());
|
||||
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
|
||||
else {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
return Err(GlobalStateManagerError::InvalidName(
|
||||
(*interface_key).clone(),
|
||||
));
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
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()
|
||||
.get_state(network_id)?;
|
||||
|
||||
// Allocate interface address
|
||||
let is_dynamic = opt_address.is_none();
|
||||
let ifv4_addr = network_state.allocate_address_v4(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Machine(self.id()),
|
||||
opt_address,
|
||||
)?;
|
||||
|
||||
// Update the network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(network_state);
|
||||
|
||||
@ -212,34 +218,38 @@ impl MachineState {
|
||||
|
||||
pub fn allocate_address_ipv6(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
interface_name: &str,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
opt_address_flags: Option<AddressFlags>,
|
||||
) -> MachineRegistryResult<Ifv6Addr> {
|
||||
) -> GlobalStateManagerResult<Ifv6Addr> {
|
||||
let interface_key = Arc::new(interface_name.to_string());
|
||||
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
|
||||
else {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
return Err(GlobalStateManagerError::InvalidName(
|
||||
(*interface_key).clone(),
|
||||
));
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
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()
|
||||
.get_state(network_id)?;
|
||||
|
||||
// Allocate interface address
|
||||
let is_dynamic = opt_address.is_none();
|
||||
let ifv6_addr = network_state.allocate_address_v6(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Machine(self.id()),
|
||||
opt_address,
|
||||
)?;
|
||||
// Update the network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(network_state);
|
||||
|
||||
@ -277,18 +287,20 @@ impl MachineState {
|
||||
|
||||
pub fn attach_network(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
interface_name: &str,
|
||||
network_id: NetworkStateId,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let interface_key = Arc::new(interface_name.to_string());
|
||||
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
|
||||
else {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
return Err(GlobalStateManagerError::InvalidName(
|
||||
(*interface_key).clone(),
|
||||
));
|
||||
};
|
||||
|
||||
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);
|
||||
@ -310,16 +322,18 @@ impl MachineState {
|
||||
|
||||
pub fn detach_network(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
interface_name: &str,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let interface_key = Arc::new(interface_name.to_string());
|
||||
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
|
||||
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
|
||||
let interfaces = self
|
||||
@ -339,7 +353,7 @@ impl MachineState {
|
||||
pub fn attached_network_interfaces(
|
||||
&self,
|
||||
network_id: NetworkStateId,
|
||||
) -> MachineRegistryResult<Vec<Arc<String>>> {
|
||||
) -> GlobalStateManagerResult<Vec<Arc<String>>> {
|
||||
let mut out = Vec::new();
|
||||
for intf in &self.fields.interfaces {
|
||||
if intf.1.network_id == Some(network_id) {
|
||||
@ -351,22 +365,26 @@ impl MachineState {
|
||||
|
||||
pub fn release_address(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
interface_name: &str,
|
||||
address: IpAddr,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let interface_key = Arc::new(interface_name.to_owned());
|
||||
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
|
||||
else {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
return Err(GlobalStateManagerError::InvalidName(
|
||||
(*interface_key).clone(),
|
||||
));
|
||||
};
|
||||
|
||||
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
|
||||
let mut network_state = machine_registry_inner
|
||||
let mut network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(network_id)?;
|
||||
|
||||
@ -377,7 +395,7 @@ impl MachineState {
|
||||
};
|
||||
|
||||
// Update the network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(network_state);
|
||||
|
||||
@ -413,16 +431,18 @@ impl MachineState {
|
||||
|
||||
pub fn release_all_addresses(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
interface_name: &str,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let interface_key = Arc::new(interface_name.to_string());
|
||||
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
|
||||
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
|
||||
let interfaces = self
|
||||
@ -442,24 +462,24 @@ impl MachineState {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn detach_network_inner(
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
machine_state_interface: &mut MachineStateInterface,
|
||||
) -> MachineRegistryResult<()> {
|
||||
Self::release_all_addresses_inner(machine_registry_inner, machine_state_interface)?;
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
Self::release_all_addresses_inner(gsm_inner, machine_state_interface)?;
|
||||
machine_state_interface.network_id = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release_all_addresses_inner(
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
machine_state_interface: &mut MachineStateInterface,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let Some(network_id) = machine_state_interface.network_id else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let mut network_state = machine_registry_inner
|
||||
let mut network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(network_id)?;
|
||||
|
||||
@ -472,7 +492,7 @@ impl MachineState {
|
||||
}
|
||||
|
||||
// Update the network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(network_state);
|
||||
|
||||
@ -488,16 +508,18 @@ impl MachineState {
|
||||
|
||||
pub fn release_interface(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
interface_name: &str,
|
||||
) -> MachineRegistryResult<()> {
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let interface_key = Arc::new(interface_name.to_string());
|
||||
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
|
||||
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
|
||||
let interfaces = self.fields.interfaces.without(&interface_key);
|
||||
@ -513,8 +535,8 @@ impl MachineState {
|
||||
|
||||
pub fn release_all_interfaces(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<()> {
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let interface_names: Vec<String> = self
|
||||
.fields
|
||||
.interfaces
|
||||
@ -526,10 +548,12 @@ impl MachineState {
|
||||
let Some(mut machine_state_interface) =
|
||||
self.fields.interfaces.get(&interface_key).cloned()
|
||||
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
|
@ -4,7 +4,7 @@ mod machine_state;
|
||||
mod network_locations_list;
|
||||
mod network_state;
|
||||
mod profile_state;
|
||||
mod state_allocator;
|
||||
mod state_registry;
|
||||
mod template_state;
|
||||
|
||||
use super::*;
|
||||
@ -15,5 +15,5 @@ pub use machine_state::*;
|
||||
pub use network_locations_list::*;
|
||||
pub use network_state::*;
|
||||
pub use profile_state::*;
|
||||
pub use state_allocator::*;
|
||||
pub use state_registry::*;
|
||||
pub use template_state::*;
|
@ -20,9 +20,9 @@ pub struct NetworkLocation<T> {
|
||||
impl NetworkLocationsList {
|
||||
pub fn pick_v4(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
prefix: &WeightedList<u8>,
|
||||
) -> MachineRegistryResult<NetworkLocation<Ipv4Net>> {
|
||||
) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv4Net>>> {
|
||||
// Get maximum prefix
|
||||
let max_prefix = prefix
|
||||
.iter()
|
||||
@ -36,9 +36,8 @@ impl NetworkLocationsList {
|
||||
// Get allocations which have subnets that would fit
|
||||
// our maximum requested prefix
|
||||
let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| {
|
||||
let allocation = machine_registry_inner
|
||||
.config()
|
||||
.allocations
|
||||
let allocation = gsm_inner
|
||||
.allocations()
|
||||
.get(allocation_name)
|
||||
.expect("must exist");
|
||||
Ok(allocation
|
||||
@ -48,48 +47,42 @@ impl NetworkLocationsList {
|
||||
.and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix)))
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Pick an allocation
|
||||
let subnets = machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice_ref(&alloc_subnets);
|
||||
let subnets = gsm_inner.srng().weighted_choice_ref(&alloc_subnets);
|
||||
|
||||
// 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
|
||||
let opt_subnet = prefix
|
||||
.filter(|p| *p >= net.prefix_len())
|
||||
.as_ref()
|
||||
.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
|
||||
let mut address_pool = AddressPool::<()>::new();
|
||||
address_pool.add_scope_v4(net);
|
||||
address_pool.allocate_random_v4(
|
||||
machine_registry_inner.srng(),
|
||||
subnet_prefix,
|
||||
(),
|
||||
)
|
||||
address_pool.allocate_random_v4(gsm_inner.srng(), subnet_prefix, ())
|
||||
})
|
||||
.transpose()?
|
||||
.flatten();
|
||||
let Some(subnet) = opt_subnet else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
Ok(NetworkLocation {
|
||||
Ok(Some(NetworkLocation {
|
||||
subnet,
|
||||
super_net: None,
|
||||
})
|
||||
}))
|
||||
}
|
||||
NetworkLocationsList::Networks { networks } => {
|
||||
// Get networks which have subnets that would fit
|
||||
// our maximum requested prefix
|
||||
let Some(available_networks) = networks.try_filter(|network_id| {
|
||||
let super_network_state = machine_registry_inner
|
||||
let super_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(*network_id)
|
||||
.expect("must exist");
|
||||
@ -97,14 +90,12 @@ impl NetworkLocationsList {
|
||||
Ok(super_network_state.can_allocate_subnet_v4(None, max_prefix))
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Pick a network
|
||||
let super_network_id = *machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice_ref(&available_networks);
|
||||
let mut super_network_state = machine_registry_inner
|
||||
let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks);
|
||||
let mut super_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(super_network_id)
|
||||
.expect("must exist");
|
||||
@ -114,11 +105,11 @@ impl NetworkLocationsList {
|
||||
.filter(|p| super_network_state.can_allocate_subnet_v4(None, *p))
|
||||
.as_ref()
|
||||
.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
|
||||
super_network_state.allocate_subnet_v4(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Network(super_network_state.id()),
|
||||
None,
|
||||
subnet_prefix,
|
||||
@ -126,27 +117,27 @@ impl NetworkLocationsList {
|
||||
})
|
||||
.transpose()?;
|
||||
let Some(subnet) = opt_subnet else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Update network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(super_network_state);
|
||||
|
||||
Ok(NetworkLocation {
|
||||
Ok(Some(NetworkLocation {
|
||||
subnet,
|
||||
super_net: Some(super_network_id),
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pick_v6(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
prefix: &WeightedList<u8>,
|
||||
) -> MachineRegistryResult<NetworkLocation<Ipv6Net>> {
|
||||
) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv6Net>>> {
|
||||
// Get maximum prefix
|
||||
let max_prefix = prefix
|
||||
.iter()
|
||||
@ -160,9 +151,8 @@ impl NetworkLocationsList {
|
||||
// Get allocations which have subnets that would fit
|
||||
// our maximum requested prefix
|
||||
let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| {
|
||||
let allocation = machine_registry_inner
|
||||
.config()
|
||||
.allocations
|
||||
let allocation = gsm_inner
|
||||
.allocations()
|
||||
.get(allocation_name)
|
||||
.expect("must exist");
|
||||
Ok(allocation
|
||||
@ -172,48 +162,42 @@ impl NetworkLocationsList {
|
||||
.and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix)))
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Pick an allocation
|
||||
let subnets = machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice_ref(&alloc_subnets);
|
||||
let subnets = gsm_inner.srng().weighted_choice_ref(&alloc_subnets);
|
||||
|
||||
// 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
|
||||
let opt_subnet = prefix
|
||||
.filter(|p| *p >= net.prefix_len())
|
||||
.as_ref()
|
||||
.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
|
||||
let mut address_pool = AddressPool::<()>::new();
|
||||
address_pool.add_scope_v6(net);
|
||||
address_pool.allocate_random_v6(
|
||||
machine_registry_inner.srng(),
|
||||
subnet_prefix,
|
||||
(),
|
||||
)
|
||||
address_pool.allocate_random_v6(gsm_inner.srng(), subnet_prefix, ())
|
||||
})
|
||||
.transpose()?
|
||||
.flatten();
|
||||
let Some(subnet) = opt_subnet else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
Ok(NetworkLocation {
|
||||
Ok(Some(NetworkLocation {
|
||||
subnet,
|
||||
super_net: None,
|
||||
})
|
||||
}))
|
||||
}
|
||||
NetworkLocationsList::Networks { networks } => {
|
||||
// Get networks which have subnets that would fit
|
||||
// our maximum requested prefix
|
||||
let Some(available_networks) = networks.try_filter(|network_id| {
|
||||
let super_network_state = machine_registry_inner
|
||||
let super_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(*network_id)
|
||||
.expect("must exist");
|
||||
@ -221,14 +205,12 @@ impl NetworkLocationsList {
|
||||
Ok(super_network_state.can_allocate_subnet_v6(None, max_prefix))
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Pick a network
|
||||
let super_network_id = *machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice_ref(&available_networks);
|
||||
let mut super_network_state = machine_registry_inner
|
||||
let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks);
|
||||
let mut super_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(super_network_id)
|
||||
.expect("must exist");
|
||||
@ -238,11 +220,11 @@ impl NetworkLocationsList {
|
||||
.filter(|p| super_network_state.can_allocate_subnet_v6(None, *p))
|
||||
.as_ref()
|
||||
.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
|
||||
super_network_state.allocate_subnet_v6(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Network(super_network_state.id()),
|
||||
None,
|
||||
subnet_prefix,
|
||||
@ -250,18 +232,18 @@ impl NetworkLocationsList {
|
||||
})
|
||||
.transpose()?;
|
||||
let Some(subnet) = opt_subnet else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Update network state
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(super_network_state);
|
||||
|
||||
Ok(NetworkLocation {
|
||||
Ok(Some(NetworkLocation {
|
||||
subnet,
|
||||
super_net: Some(super_network_id),
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
let mut blueprint_state = machine_registry_inner
|
||||
let mut blueprint_state = gsm_inner
|
||||
.blueprint_states()
|
||||
.get_state(generating_blueprint)
|
||||
.expect("must exist");
|
||||
blueprint_state.on_network_released(self.id());
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.blueprint_states_mut()
|
||||
.set_state(blueprint_state)
|
||||
}
|
||||
@ -159,25 +159,29 @@ impl NetworkState {
|
||||
|
||||
pub fn clear_ipv4(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<()> {
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let Some(ipv4) = self.fields.ipv4.clone() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
address_pool.clear_ipv4(|_n, t| match t {
|
||||
OwnerTag::Machine(_) => true,
|
||||
OwnerTag::Network(nsid) => *nsid != self.id(),
|
||||
OwnerTag::Gateway(nsid) => *nsid != self.id(),
|
||||
})?;
|
||||
address_pool
|
||||
.clear_ipv4(|_n, t| match t {
|
||||
OwnerTag::Machine(_) => true,
|
||||
OwnerTag::Network(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 it belongs to a different network
|
||||
if let Some(gateway) = ipv4.gateway.as_ref() {
|
||||
if gateway.params.external_network != self.id() {
|
||||
// Get the external network state
|
||||
let mut external_network_state = machine_registry_inner
|
||||
let mut external_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(gateway.params.external_network)
|
||||
.expect("must succeed");
|
||||
@ -188,7 +192,7 @@ impl NetworkState {
|
||||
.expect("must succeed");
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
}
|
||||
@ -206,11 +210,11 @@ impl NetworkState {
|
||||
|
||||
pub fn set_ipv4(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
params: NetworkStateIpv4Params,
|
||||
gateway_params: Option<NetworkStateIpv4GatewayParams>,
|
||||
) -> MachineRegistryResult<()> {
|
||||
self.clear_ipv4(machine_registry_inner)?;
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
self.clear_ipv4(gsm_inner)?;
|
||||
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
address_pool.add_scope_v4(params.allocation);
|
||||
@ -227,12 +231,12 @@ impl NetworkState {
|
||||
internal_address
|
||||
} else {
|
||||
let Some(internal_address) = address_pool.allocate_random_v4(
|
||||
machine_registry_inner.srng(),
|
||||
gsm_inner.srng(),
|
||||
32,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
};
|
||||
internal_address.addr()
|
||||
};
|
||||
@ -245,7 +249,7 @@ impl NetworkState {
|
||||
};
|
||||
|
||||
// Get the external network state
|
||||
let mut external_network_state = machine_registry_inner
|
||||
let mut external_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(gateway_params.external_network)
|
||||
.expect("must succeed");
|
||||
@ -256,7 +260,7 @@ impl NetworkState {
|
||||
// If the translation mode is 'none', then the external and internal
|
||||
// addresses must be the same
|
||||
external_network_state.allocate_address_v4(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
Some(internal_address),
|
||||
)?
|
||||
@ -264,14 +268,14 @@ impl NetworkState {
|
||||
// Network translation means the internal and external addresses
|
||||
// will be different
|
||||
external_network_state.allocate_address_v4(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
None,
|
||||
)?
|
||||
};
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
|
||||
@ -299,25 +303,29 @@ impl NetworkState {
|
||||
|
||||
pub fn clear_ipv6(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<()> {
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
let Some(ipv6) = self.fields.ipv6.clone() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
address_pool.clear_ipv6(|_n, t| match t {
|
||||
OwnerTag::Machine(_) => true,
|
||||
OwnerTag::Network(nsid) => *nsid != self.id(),
|
||||
OwnerTag::Gateway(nsid) => *nsid != self.id(),
|
||||
})?;
|
||||
address_pool
|
||||
.clear_ipv6(|_n, t| match t {
|
||||
OwnerTag::Machine(_) => true,
|
||||
OwnerTag::Network(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 it belongs to a different network
|
||||
if let Some(gateway) = ipv6.gateway.as_ref() {
|
||||
if gateway.params.external_network != self.id() {
|
||||
// Get the external network state
|
||||
let mut external_network_state = machine_registry_inner
|
||||
let mut external_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(gateway.params.external_network)
|
||||
.expect("must succeed");
|
||||
@ -328,7 +336,7 @@ impl NetworkState {
|
||||
.expect("must succeed");
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
}
|
||||
@ -345,11 +353,11 @@ impl NetworkState {
|
||||
}
|
||||
pub fn set_ipv6(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
params: NetworkStateIpv6Params,
|
||||
gateway_params: Option<NetworkStateIpv6GatewayParams>,
|
||||
) -> MachineRegistryResult<()> {
|
||||
self.clear_ipv6(machine_registry_inner)?;
|
||||
) -> GlobalStateManagerResult<()> {
|
||||
self.clear_ipv6(gsm_inner)?;
|
||||
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
address_pool.add_scope_v6(params.allocation);
|
||||
@ -366,12 +374,12 @@ impl NetworkState {
|
||||
internal_address
|
||||
} else {
|
||||
let Some(internal_address) = address_pool.allocate_random_v6(
|
||||
machine_registry_inner.srng(),
|
||||
gsm_inner.srng(),
|
||||
128,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
};
|
||||
internal_address.addr()
|
||||
};
|
||||
@ -384,7 +392,7 @@ impl NetworkState {
|
||||
};
|
||||
|
||||
// Get the external network state
|
||||
let mut external_network_state = machine_registry_inner
|
||||
let mut external_network_state = gsm_inner
|
||||
.network_states()
|
||||
.get_state(gateway_params.external_network)
|
||||
.expect("must succeed");
|
||||
@ -395,7 +403,7 @@ impl NetworkState {
|
||||
// If the translation mode is 'none', then the external and internal
|
||||
// addresses must be the same
|
||||
external_network_state.allocate_address_v6(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
Some(internal_address),
|
||||
)?
|
||||
@ -403,14 +411,14 @@ impl NetworkState {
|
||||
// Network translation means the internal and external addresses
|
||||
// will be different
|
||||
external_network_state.allocate_address_v6(
|
||||
machine_registry_inner,
|
||||
gsm_inner,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
None,
|
||||
)?
|
||||
};
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
|
||||
@ -444,7 +452,7 @@ impl NetworkState {
|
||||
self.fields.ipv6.is_some()
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> MachineRegistryResult<bool> {
|
||||
pub fn is_active(&self) -> GlobalStateManagerResult<bool> {
|
||||
let mut can_allocate = false;
|
||||
|
||||
if self.fields.ipv4.is_some() {
|
||||
@ -464,11 +472,11 @@ impl NetworkState {
|
||||
|
||||
pub fn allocate_address_v4(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
) -> MachineRegistryResult<Ifv4Addr> {
|
||||
let net = self.allocate_subnet_v4(machine_registry_inner, owner_tag, opt_address, 32)?;
|
||||
) -> GlobalStateManagerResult<Ifv4Addr> {
|
||||
let net = self.allocate_subnet_v4(gsm_inner, owner_tag, opt_address, 32)?;
|
||||
let ip = net.addr();
|
||||
|
||||
let ipv4 = self.fields.ipv4.as_ref().unwrap();
|
||||
@ -490,13 +498,13 @@ impl NetworkState {
|
||||
|
||||
pub fn allocate_subnet_v4(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
prefix: u8,
|
||||
) -> MachineRegistryResult<Ipv4Net> {
|
||||
) -> GlobalStateManagerResult<Ipv4Net> {
|
||||
if self.fields.ipv4.is_none() {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
}
|
||||
|
||||
// See if we are requesting a specific address
|
||||
@ -510,12 +518,12 @@ impl NetworkState {
|
||||
} else {
|
||||
// Get a random address if available
|
||||
let Some(allocation) = address_pool.allocate_random_v4(
|
||||
machine_registry_inner.srng(),
|
||||
gsm_inner.srng(),
|
||||
prefix,
|
||||
owner_tag,
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
};
|
||||
allocation
|
||||
};
|
||||
@ -551,11 +559,14 @@ impl NetworkState {
|
||||
pub fn release_address_v4(
|
||||
&mut self,
|
||||
addr: Ipv4Addr,
|
||||
) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
) -> GlobalStateManagerResult<Option<OwnerTag>> {
|
||||
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 opt_tag = address_pool.release_allocation_v4(net)?;
|
||||
|
||||
@ -569,11 +580,11 @@ impl NetworkState {
|
||||
|
||||
pub fn allocate_address_v6(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
) -> MachineRegistryResult<Ifv6Addr> {
|
||||
let net = self.allocate_subnet_v6(machine_registry_inner, owner_tag, opt_address, 128)?;
|
||||
) -> GlobalStateManagerResult<Ifv6Addr> {
|
||||
let net = self.allocate_subnet_v6(gsm_inner, owner_tag, opt_address, 128)?;
|
||||
let ip = net.addr();
|
||||
|
||||
let ipv6 = self.fields.ipv6.as_ref().unwrap();
|
||||
@ -595,13 +606,13 @@ impl NetworkState {
|
||||
|
||||
pub fn allocate_subnet_v6(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
prefix: u8,
|
||||
) -> MachineRegistryResult<Ipv6Net> {
|
||||
) -> GlobalStateManagerResult<Ipv6Net> {
|
||||
if self.fields.ipv6.is_none() {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
}
|
||||
|
||||
// See if we are requesting a specific address
|
||||
@ -615,12 +626,12 @@ impl NetworkState {
|
||||
} else {
|
||||
// Get a random address if available
|
||||
let Some(allocation) = address_pool.allocate_random_v6(
|
||||
machine_registry_inner.srng(),
|
||||
gsm_inner.srng(),
|
||||
prefix,
|
||||
owner_tag,
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
return Err(GlobalStateManagerError::NoAllocation);
|
||||
};
|
||||
allocation
|
||||
};
|
||||
@ -656,11 +667,14 @@ impl NetworkState {
|
||||
pub fn release_address_v6(
|
||||
&mut self,
|
||||
addr: Ipv6Addr,
|
||||
) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
) -> GlobalStateManagerResult<Option<OwnerTag>> {
|
||||
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 opt_tag = address_pool.release_allocation_v6(net)?;
|
||||
|
@ -4,6 +4,10 @@ use std::marker::PhantomData;
|
||||
pub trait State: fmt::Debug + Clone {
|
||||
fn id(&self) -> StateId<Self>;
|
||||
fn name(&self) -> Option<String>;
|
||||
fn debug_name(&self) -> String {
|
||||
self.name()
|
||||
.unwrap_or_else(|| format!("<{}>", self.id().external_id()))
|
||||
}
|
||||
}
|
||||
|
||||
type StateIdInternal = u64;
|
||||
@ -44,14 +48,14 @@ impl<S: State> core::hash::Hash for StateId<S> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StateAllocator<S: State> {
|
||||
pub struct StateRegistry<S: State> {
|
||||
state_id_by_name: imbl::HashMap<Arc<String>, StateIdInternal>,
|
||||
state_by_id: imbl::HashMap<StateIdInternal, Option<S>>,
|
||||
next_state_id: StateIdInternal,
|
||||
free_state_ids: imbl::Vector<StateIdInternal>,
|
||||
}
|
||||
|
||||
impl<S: State> StateAllocator<S> {
|
||||
impl<S: State> StateRegistry<S> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state_id_by_name: imbl::HashMap::new(),
|
||||
@ -90,10 +94,10 @@ impl<S: State> StateAllocator<S> {
|
||||
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
|
||||
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
|
||||
@ -112,24 +116,24 @@ impl<S: State> StateAllocator<S> {
|
||||
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
|
||||
let id = state.id();
|
||||
|
||||
// Get the allocator slot
|
||||
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
|
||||
if opt_state.is_some() {
|
||||
return Err(MachineRegistryError::AlreadyAttached);
|
||||
return Err(GlobalStateManagerError::AlreadyAttached);
|
||||
}
|
||||
|
||||
// Ensure the name isn't duplicated
|
||||
if let Some(name) = state.name() {
|
||||
if self.state_id_by_name.contains_key(&name) {
|
||||
return Err(MachineRegistryError::DuplicateName);
|
||||
return Err(GlobalStateManagerError::DuplicateName(name));
|
||||
}
|
||||
// Register the named state
|
||||
self.state_id_by_name
|
||||
@ -143,15 +147,15 @@ impl<S: State> StateAllocator<S> {
|
||||
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
|
||||
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
|
||||
let Some(state) = opt_state.take() else {
|
||||
return Err(MachineRegistryError::NotAttached);
|
||||
return Err(GlobalStateManagerError::NotAttached);
|
||||
};
|
||||
|
||||
// Release the name if it exists
|
||||
@ -166,13 +170,13 @@ impl<S: State> StateAllocator<S> {
|
||||
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
|
||||
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 {
|
||||
return Err(MachineRegistryError::NotAttached);
|
||||
return Err(GlobalStateManagerError::NotAttached);
|
||||
};
|
||||
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 {
|
||||
Self::new()
|
||||
}
|
@ -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
|
||||
let backup = machine_registry_inner.clone();
|
||||
let backup = gsm_inner.clone();
|
||||
|
||||
// Make a copy of this template state
|
||||
let mut current_state = self.clone();
|
||||
|
||||
// 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
|
||||
*machine_registry_inner = backup;
|
||||
*gsm_inner = backup;
|
||||
|
||||
// Return if this worked or not
|
||||
ok
|
||||
}
|
||||
|
||||
/// 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
|
||||
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
|
||||
@ -144,26 +144,28 @@ impl TemplateState {
|
||||
|
||||
pub fn generate(
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<MachineStateId> {
|
||||
gsm_inner: &mut GlobalStateManagerInner,
|
||||
) -> GlobalStateManagerResult<MachineStateId> {
|
||||
// See if we have reached our machine limit
|
||||
if let Some(limit_machine_count) = self.fields.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
|
||||
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
|
||||
let network_state =
|
||||
locations_list.pick(machine_registry_inner, |_, x| self.network_filter(x))?;
|
||||
let Some(network_state) = locations_list.pick(gsm_inner, |_, x| self.network_filter(x))?
|
||||
else {
|
||||
return Err(GlobalStateManagerError::TemplateComplete(self.debug_name()));
|
||||
};
|
||||
|
||||
// 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
|
||||
let mut machine_state =
|
||||
@ -183,18 +185,18 @@ impl TemplateState {
|
||||
|
||||
// Make the default route interface
|
||||
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() {
|
||||
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() {
|
||||
machine_state.allocate_address_ipv6(machine_registry_inner, &vin0, None, None)?;
|
||||
machine_state.allocate_address_ipv6(gsm_inner, &vin0, None, None)?;
|
||||
}
|
||||
Ok(())
|
||||
})() {
|
||||
// Release the machine state and id if things failed to allocate
|
||||
machine_state.release(machine_registry_inner);
|
||||
machine_registry_inner
|
||||
machine_state.release(gsm_inner);
|
||||
gsm_inner
|
||||
.machine_states_mut()
|
||||
.release_id(machine_state_id)
|
||||
.expect("must succeed");
|
||||
@ -202,7 +204,7 @@ impl TemplateState {
|
||||
}
|
||||
|
||||
// Attach the state to the id
|
||||
machine_registry_inner
|
||||
gsm_inner
|
||||
.machine_states_mut()
|
||||
.attach_state(machine_state)
|
||||
.expect("must succeed");
|
||||
@ -217,7 +219,7 @@ impl TemplateState {
|
||||
.fields
|
||||
.limit_machines_per_network
|
||||
.as_ref()
|
||||
.map(|wl| *machine_registry_inner.srng().weighted_choice_ref(wl));
|
||||
.map(|wl| *gsm_inner.srng().weighted_choice_ref(wl));
|
||||
PerNetworkInfo {
|
||||
limit_machine_count,
|
||||
machines: imbl::HashSet::new(),
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
pub mod config;
|
||||
mod machine_registry;
|
||||
mod global_state_manager;
|
||||
mod server_processor;
|
||||
mod stable_rng;
|
||||
mod weighted_list;
|
||||
|
||||
use super::*;
|
||||
|
||||
use machine_registry::*;
|
||||
use global_state_manager::*;
|
||||
use server_processor::*;
|
||||
use stable_rng::*;
|
||||
use weighted_list::*;
|
||||
@ -26,6 +26,8 @@ pub enum RouterServerError {
|
||||
SerializationError(postcard::Error),
|
||||
#[error("IO Error: {0}")]
|
||||
IoError(io::ErrorKind),
|
||||
#[error("State Error: {0}")]
|
||||
StateError(global_state_manager::GlobalStateManagerError),
|
||||
}
|
||||
|
||||
pub type RouterServerResult<T> = Result<T, RouterServerError>;
|
||||
@ -40,10 +42,10 @@ enum RunLoopEvent {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RouterServerUnlockedInner {
|
||||
config: config::Config,
|
||||
new_client_sender: flume::Sender<SendPinBoxFuture<RunLoopEvent>>,
|
||||
new_client_receiver: flume::Receiver<SendPinBoxFuture<RunLoopEvent>>,
|
||||
server_processor: ServerProcessor,
|
||||
global_state_manager: GlobalStateManager,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -60,69 +62,44 @@ pub struct RouterServer {
|
||||
inner: Arc<Mutex<RouterServerInner>>,
|
||||
}
|
||||
|
||||
impl Default for RouterServer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl RouterServer {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Public Interface
|
||||
|
||||
/// 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
|
||||
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
|
||||
let server_processor = ServerProcessor::new(config.clone());
|
||||
let server_processor = ServerProcessor::new(global_state_manager.clone());
|
||||
|
||||
Self {
|
||||
unlocked_inner: Arc::new(RouterServerUnlockedInner {
|
||||
config,
|
||||
new_client_sender,
|
||||
new_client_receiver,
|
||||
server_processor,
|
||||
global_state_manager,
|
||||
}),
|
||||
inner: Arc::new(Mutex::new(RouterServerInner {})),
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
/// Execute a config file on the global state manager
|
||||
pub fn execute_config(&self, cfg: config::Config) -> RouterServerResult<()> {
|
||||
self.unlocked_inner
|
||||
.global_state_manager
|
||||
.execute_config(cfg)
|
||||
.map_err(RouterServerError::StateError)
|
||||
}
|
||||
|
||||
/// Accept RouterClient connections on a TCP socket
|
||||
@ -329,4 +306,46 @@ impl RouterServer {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,9 @@ struct ServerProcessorInner {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ServerProcessorUnlockedInner {
|
||||
config: config::Config,
|
||||
machine_registry: GlobalStateManager,
|
||||
receiver: flume::Receiver<ServerProcessorCommandRecord>,
|
||||
sender: flume::Sender<ServerProcessorCommandRecord>,
|
||||
|
||||
machine_registry: MachineRegistry,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -29,15 +27,14 @@ impl ServerProcessor {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Public Interface
|
||||
|
||||
pub fn new(config: config::Config) -> Self {
|
||||
pub fn new(machine_registry: GlobalStateManager) -> Self {
|
||||
let (sender, receiver) = flume::unbounded();
|
||||
|
||||
Self {
|
||||
unlocked_inner: Arc::new(ServerProcessorUnlockedInner {
|
||||
config: config.clone(),
|
||||
sender,
|
||||
receiver,
|
||||
machine_registry: MachineRegistry::new(config),
|
||||
machine_registry,
|
||||
}),
|
||||
inner: Arc::new(Mutex::new(ServerProcessorInner {})),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user