mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-03-30 17:48:03 -04:00
[skip ci] network and blueprint code
This commit is contained in:
parent
c0680aa712
commit
8906ad1d88
@ -1,5 +1,3 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -137,11 +135,9 @@ impl MachineRegistryInner {
|
|||||||
self.allocated_machines.remove(&id);
|
self.allocated_machines.remove(&id);
|
||||||
} else {
|
} else {
|
||||||
// Was a templated machine, so remove the machine state
|
// Was a templated machine, so remove the machine state
|
||||||
let Some(machine_state) = self.machine_states().get_state(id)? else {
|
let machine_state = self.machine_states().get_state(id)?;
|
||||||
return Err(MachineRegistryError::InvalidId);
|
|
||||||
};
|
|
||||||
machine_state.release(self);
|
machine_state.release(self);
|
||||||
self.machine_states().release_id(id)?;
|
self.machine_states_mut().release_id(id)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -150,19 +146,35 @@ impl MachineRegistryInner {
|
|||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
/// Private Implementation
|
/// Private Implementation
|
||||||
|
|
||||||
pub(super) fn profile_states(&mut self) -> &mut StateAllocator<ProfileState> {
|
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 profile_states_mut(&mut self) -> &mut StateAllocator<ProfileState> {
|
||||||
&mut self.profile_state_allocator
|
&mut self.profile_state_allocator
|
||||||
}
|
}
|
||||||
pub(super) fn machine_states(&mut self) -> &mut StateAllocator<MachineState> {
|
pub(super) fn machine_states_mut(&mut self) -> &mut StateAllocator<MachineState> {
|
||||||
&mut self.machine_state_allocator
|
&mut self.machine_state_allocator
|
||||||
}
|
}
|
||||||
pub(super) fn template_states(&mut self) -> &mut StateAllocator<TemplateState> {
|
pub(super) fn template_states_mut(&mut self) -> &mut StateAllocator<TemplateState> {
|
||||||
&mut self.template_state_allocator
|
&mut self.template_state_allocator
|
||||||
}
|
}
|
||||||
pub(super) fn network_states(&mut self) -> &mut StateAllocator<NetworkState> {
|
pub(super) fn network_states_mut(&mut self) -> &mut StateAllocator<NetworkState> {
|
||||||
&mut self.network_state_allocator
|
&mut self.network_state_allocator
|
||||||
}
|
}
|
||||||
pub(super) fn blueprint_states(&mut self) -> &mut StateAllocator<BlueprintState> {
|
pub(super) fn blueprint_states_mut(&mut self) -> &mut StateAllocator<BlueprintState> {
|
||||||
&mut self.blueprint_state_allocator
|
&mut self.blueprint_state_allocator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ mod machine_registry_inner;
|
|||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use ipnet::*;
|
|
||||||
|
|
||||||
use address_pool::*;
|
use address_pool::*;
|
||||||
use machine_registry_inner::*;
|
use machine_registry_inner::*;
|
||||||
@ -23,7 +22,7 @@ pub enum MachineRegistryError {
|
|||||||
InvalidId,
|
InvalidId,
|
||||||
InvalidName,
|
InvalidName,
|
||||||
AlreadyAttached,
|
AlreadyAttached,
|
||||||
AlreadyDetached,
|
NotAttached,
|
||||||
DuplicateName,
|
DuplicateName,
|
||||||
ProfileComplete,
|
ProfileComplete,
|
||||||
TemplateComplete,
|
TemplateComplete,
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
pub enum Availability<T> {
|
|
||||||
None,
|
|
||||||
Existing(T),
|
|
||||||
New,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Copy> Copy for Availability<T> {}
|
|
||||||
|
|
||||||
impl<T: Clone> Clone for Availability<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
match self {
|
|
||||||
Availability::None => Availability::None,
|
|
||||||
Availability::Existing(x) => Availability::Existing(x.clone()),
|
|
||||||
Availability::New => Availability::New,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for Availability<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Availability::None => f.write_str("None"),
|
|
||||||
Availability::Existing(x) => f.debug_tuple("Existing").field(x).finish(),
|
|
||||||
Availability::New => f.write_str("New"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,10 +6,56 @@ struct BlueprintStateUnlockedInner {
|
|||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BlueprintStateIpv4Params {
|
||||||
|
pub allocation: Option<String>,
|
||||||
|
pub additional_prefix: u8,
|
||||||
|
pub gateway: Option<BlueprintStateGatewayParams>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BlueprintStateIpv6Params {
|
||||||
|
pub allocation: Option<String>,
|
||||||
|
pub additional_prefix: u8,
|
||||||
|
pub gateway: Option<BlueprintStateGatewayParams>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BlueprintStateGatewayParams {
|
||||||
|
pub translation: WeightedList<config::Translation>,
|
||||||
|
pub upnp: Probability,
|
||||||
|
pub network: Option<NetworkStateId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BlueprintStateIpv4 {
|
||||||
|
params: BlueprintStateIpv4Params,
|
||||||
|
gateway: Option<BlueprintStateIpv4Gateway>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BlueprintStateIpv6 {
|
||||||
|
params: BlueprintStateIpv6Params,
|
||||||
|
gateway: Option<BlueprintStateIpv6Gateway>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BlueprintStateIpv4Gateway {
|
||||||
|
params: BlueprintStateGatewayParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BlueprintStateIpv6Gateway {
|
||||||
|
params: BlueprintStateGatewayParams,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct BlueprintStateInner {
|
struct BlueprintStateInner {
|
||||||
limit_network_count: Option<usize>,
|
limit_network_count: Option<usize>,
|
||||||
networks: Vec<NetworkStateId>,
|
networks: Vec<NetworkStateId>,
|
||||||
|
model: Option<WeightedList<String>>,
|
||||||
|
ipv4: Option<BlueprintStateIpv4>,
|
||||||
|
ipv6: Option<BlueprintStateIpv6>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -27,6 +73,9 @@ impl BlueprintState {
|
|||||||
inner: Arc::new(Mutex::new(BlueprintStateInner {
|
inner: Arc::new(Mutex::new(BlueprintStateInner {
|
||||||
limit_network_count: None,
|
limit_network_count: None,
|
||||||
networks: Vec::new(),
|
networks: Vec::new(),
|
||||||
|
model: None,
|
||||||
|
ipv4: None,
|
||||||
|
ipv6: None,
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -36,6 +85,73 @@ impl BlueprintState {
|
|||||||
inner.limit_network_count = limit_network_count;
|
inner.limit_network_count = limit_network_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_model(&self, model: WeightedList<String>) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.model = Some(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ipv4(
|
||||||
|
&self,
|
||||||
|
params: BlueprintStateIpv4Params,
|
||||||
|
gateway_params: Option<BlueprintStateGatewayParams>,
|
||||||
|
) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if inner.ipv4.is_none() {
|
||||||
|
inner.ipv4 = Some(BlueprintStateIpv4 {
|
||||||
|
params,
|
||||||
|
gateway: None,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
inner.ipv4.as_mut().map(|ipv4| {
|
||||||
|
ipv4.params = params;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let ipv4 = inner.ipv4.as_mut().expect("must exist");
|
||||||
|
|
||||||
|
if ipv4.gateway.is_some() {
|
||||||
|
if let Some(gateway_params) = gateway_params {
|
||||||
|
ipv4.gateway.as_mut().expect("must exist").params = gateway_params;
|
||||||
|
} else {
|
||||||
|
ipv4.gateway = None;
|
||||||
|
}
|
||||||
|
} else if let Some(gateway_params) = gateway_params {
|
||||||
|
ipv4.gateway = Some(BlueprintStateIpv4Gateway {
|
||||||
|
params: gateway_params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ipv6(
|
||||||
|
&self,
|
||||||
|
params: BlueprintStateIpv6Params,
|
||||||
|
gateway_params: Option<BlueprintStateGatewayParams>,
|
||||||
|
) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if inner.ipv6.is_none() {
|
||||||
|
inner.ipv6 = Some(BlueprintStateIpv6 {
|
||||||
|
params,
|
||||||
|
gateway: None,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
inner.ipv6.as_mut().map(|ipv6| {
|
||||||
|
ipv6.params = params;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let ipv6 = inner.ipv6.as_mut().expect("must exist");
|
||||||
|
|
||||||
|
if ipv6.gateway.is_some() {
|
||||||
|
if let Some(gateway_params) = gateway_params {
|
||||||
|
ipv6.gateway.as_mut().expect("must exist").params = gateway_params;
|
||||||
|
} else {
|
||||||
|
ipv6.gateway = None;
|
||||||
|
}
|
||||||
|
} else if let Some(gateway_params) = gateway_params {
|
||||||
|
ipv6.gateway = Some(BlueprintStateIpv6Gateway {
|
||||||
|
params: gateway_params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_active(&self) -> MachineRegistryResult<bool> {
|
pub fn is_active(&self) -> MachineRegistryResult<bool> {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
|
|
||||||
@ -49,16 +165,77 @@ impl BlueprintState {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(
|
fn generate_model_inner(
|
||||||
&self,
|
inner: &mut BlueprintStateInner,
|
||||||
machine_registry_inner: &MachineRegistryInner,
|
machine_registry_inner: &mut MachineRegistryInner,
|
||||||
) -> MachineRegistryResult<NetworkState> {
|
network_state: NetworkState,
|
||||||
|
) -> MachineRegistryResult<()> {
|
||||||
|
xxx do generation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_ipv4_inner(
|
||||||
|
inner: &mut BlueprintStateInner,
|
||||||
|
machine_registry_inner: &mut MachineRegistryInner,
|
||||||
|
network_state: NetworkState,
|
||||||
|
) -> MachineRegistryResult<()> {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_each_network_id<F, R>(&self, mut callback: F) -> MachineRegistryResult<Option<R>>
|
fn generate_ipv6_inner(
|
||||||
|
inner: &mut BlueprintStateInner,
|
||||||
|
machine_registry_inner: &mut MachineRegistryInner,
|
||||||
|
network_state: NetworkState,
|
||||||
|
) -> MachineRegistryResult<()> {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate(
|
||||||
|
&self,
|
||||||
|
machine_registry_inner: &mut MachineRegistryInner,
|
||||||
|
) -> MachineRegistryResult<NetworkState> {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
|
||||||
|
// See if there's room for another network
|
||||||
|
if let Some(limit_network_count) = inner.limit_network_count {
|
||||||
|
if inner.networks.len() >= limit_network_count {
|
||||||
|
return Err(MachineRegistryError::BlueprintComplete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a network id
|
||||||
|
let network_state_id = machine_registry_inner.network_states_mut().allocate_id();
|
||||||
|
|
||||||
|
// Create an anonymous network state
|
||||||
|
let network_state = NetworkState::new(network_state_id, None);
|
||||||
|
|
||||||
|
if let Err(e) = (|| {
|
||||||
|
Self::generate_model_inner(&mut *inner, machine_registry_inner, network_state.clone())?;
|
||||||
|
Self::generate_ipv4_inner(&mut *inner, machine_registry_inner, network_state.clone())?;
|
||||||
|
Self::generate_ipv6_inner(&mut *inner, machine_registry_inner, network_state.clone())?;
|
||||||
|
Ok(())
|
||||||
|
})() {
|
||||||
|
// Release the network state and id if things failed to allocate
|
||||||
|
network_state.release(machine_registry_inner);
|
||||||
|
machine_registry_inner
|
||||||
|
.network_states_mut()
|
||||||
|
.release_id(network_state_id);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach the state to the id
|
||||||
|
machine_registry_inner
|
||||||
|
.network_states_mut()
|
||||||
|
.attach_state(network_state.clone());
|
||||||
|
|
||||||
|
// Record the newly instantiated network
|
||||||
|
inner.networks.push(network_state_id);
|
||||||
|
|
||||||
|
Ok(network_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn for_each_network_id<F, R>(&self, callback: F) -> MachineRegistryResult<Option<R>>
|
||||||
where
|
where
|
||||||
F: FnMut(NetworkStateId) -> MachineRegistryResult<Option<R>>,
|
F: Fn(NetworkStateId) -> MachineRegistryResult<Option<R>>,
|
||||||
{
|
{
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
for network_id in &inner.networks {
|
for network_id in &inner.networks {
|
||||||
@ -68,6 +245,16 @@ impl BlueprintState {
|
|||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_network_released(&self, network_id: NetworkStateId) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
let pos = inner
|
||||||
|
.networks
|
||||||
|
.iter()
|
||||||
|
.position(|id| *id == network_id)
|
||||||
|
.expect("must exist");
|
||||||
|
inner.networks.remove(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State for BlueprintState {
|
impl State for BlueprintState {
|
||||||
|
@ -2,8 +2,14 @@ use super::*;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct MachineStateInner {
|
struct MachineStateInner {
|
||||||
|
/// The template generating this machine
|
||||||
|
generating_template: Option<TemplateStateId>,
|
||||||
/// The current network interfaces definition
|
/// The current network interfaces definition
|
||||||
interfaces: HashMap<String, MachineStateInterface>,
|
interfaces: HashMap<String, MachineStateInterface>,
|
||||||
|
/// Capabilities to disable on this machine
|
||||||
|
disable_capabilities: Vec<String>,
|
||||||
|
/// If this machine is a bootstrap
|
||||||
|
bootstrap: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -36,19 +42,45 @@ impl MachineState {
|
|||||||
Self {
|
Self {
|
||||||
unlocked_inner: Arc::new(MachineStateUnlockedInner { id, opt_name }),
|
unlocked_inner: Arc::new(MachineStateUnlockedInner { id, opt_name }),
|
||||||
inner: Arc::new(Mutex::new(MachineStateInner {
|
inner: Arc::new(Mutex::new(MachineStateInner {
|
||||||
|
generating_template: None,
|
||||||
interfaces: HashMap::new(),
|
interfaces: HashMap::new(),
|
||||||
|
disable_capabilities: Vec::new(),
|
||||||
|
bootstrap: false,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
pub fn release(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||||
self.release_all_interfaces(machine_registry_inner);
|
self.release_all_interfaces(machine_registry_inner);
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
if let Some(generating_template) = inner.generating_template {
|
||||||
|
let template_state = machine_registry_inner
|
||||||
|
.template_states_mut()
|
||||||
|
.get_state(generating_template)
|
||||||
|
.expect("must exist");
|
||||||
|
template_state.on_machine_released(self.id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn external_id(&self) -> MachineId {
|
pub fn external_id(&self) -> MachineId {
|
||||||
self.unlocked_inner.id.0
|
self.unlocked_inner.id.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_generating_template(&self, generating_template: TemplateStateId) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.generating_template = Some(generating_template);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_disable_capabilities(&self, disable_capabilities: Vec<String>) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.disable_capabilities = disable_capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_bootstrap(&self, bootstrap: bool) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.bootstrap = bootstrap
|
||||||
|
}
|
||||||
|
|
||||||
fn next_free_interface_name_inner(inner: &MachineStateInner) -> String {
|
fn next_free_interface_name_inner(inner: &MachineStateInner) -> String {
|
||||||
let mut inum = 0usize;
|
let mut inum = 0usize;
|
||||||
loop {
|
loop {
|
||||||
@ -111,12 +143,9 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the network state
|
// Get the network state
|
||||||
let Some(network_state) = machine_registry_inner
|
let network_state = machine_registry_inner
|
||||||
.network_states()
|
.network_states()
|
||||||
.get_state(intf.network_id)?
|
.get_state(intf.network_id)?;
|
||||||
else {
|
|
||||||
return Err(MachineRegistryError::NetworkNotFound);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allocate interface address
|
// Allocate interface address
|
||||||
let is_dynamic = opt_address.is_none();
|
let is_dynamic = opt_address.is_none();
|
||||||
@ -151,12 +180,9 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the network state
|
// Get the network state
|
||||||
let Some(network_state) = machine_registry_inner
|
let network_state = machine_registry_inner
|
||||||
.network_states()
|
.network_states()
|
||||||
.get_state(intf.network_id)?
|
.get_state(intf.network_id)?;
|
||||||
else {
|
|
||||||
return Err(MachineRegistryError::NetworkNotFound);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allocate interface address
|
// Allocate interface address
|
||||||
let is_dynamic = opt_address.is_none();
|
let is_dynamic = opt_address.is_none();
|
||||||
@ -190,12 +216,9 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the network state
|
// Get the network state
|
||||||
let Some(network_state) = machine_registry_inner
|
let network_state = machine_registry_inner
|
||||||
.network_states()
|
.network_states()
|
||||||
.get_state(intf.network_id)?
|
.get_state(intf.network_id)?;
|
||||||
else {
|
|
||||||
return Err(MachineRegistryError::NetworkNotFound);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Release the address from the network
|
// Release the address from the network
|
||||||
match address {
|
match address {
|
||||||
@ -230,12 +253,9 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the network state
|
// Get the network state
|
||||||
let Some(network_state) = machine_registry_inner
|
let network_state = machine_registry_inner
|
||||||
.network_states()
|
.network_states()
|
||||||
.get_state(intf.network_id)?
|
.get_state(intf.network_id)?;
|
||||||
else {
|
|
||||||
return Err(MachineRegistryError::NetworkNotFound);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Release the addresses from the network
|
// Release the addresses from the network
|
||||||
for addr in &intf.network_interface.addrs {
|
for addr in &intf.network_interface.addrs {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
mod availability;
|
|
||||||
mod blueprint_state;
|
mod blueprint_state;
|
||||||
mod machine_state;
|
mod machine_state;
|
||||||
mod network_state;
|
mod network_state;
|
||||||
@ -10,7 +9,6 @@ use std::marker::PhantomData;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub use availability::*;
|
|
||||||
pub use blueprint_state::*;
|
pub use blueprint_state::*;
|
||||||
pub use machine_state::*;
|
pub use machine_state::*;
|
||||||
pub use network_state::*;
|
pub use network_state::*;
|
||||||
|
@ -11,12 +11,10 @@ struct NetworkStateUnlockedInner {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct NetworkStateInner {
|
struct NetworkStateInner {
|
||||||
/// Network latency distribution
|
/// The blueprint generating this network
|
||||||
latency: Option<config::Distribution>,
|
generating_blueprint: Option<BlueprintStateId>,
|
||||||
/// Distance simulation metric
|
/// Model for this network
|
||||||
distance: Option<config::Distance>,
|
model: NetworkStateModel,
|
||||||
/// Packet loss probability
|
|
||||||
loss: Probability,
|
|
||||||
/// IPv4 state if it is enabled
|
/// IPv4 state if it is enabled
|
||||||
ipv4: Option<NetworkStateIpv4>,
|
ipv4: Option<NetworkStateIpv4>,
|
||||||
/// IPv6 state if it is enabled
|
/// IPv6 state if it is enabled
|
||||||
@ -24,26 +22,57 @@ struct NetworkStateInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct NetworkStateIpv4 {
|
struct NetworkStateModel {
|
||||||
|
/// Network latency distribution
|
||||||
|
latency: Option<config::Distribution>,
|
||||||
|
/// Distance simulation metric
|
||||||
|
distance: Option<config::Distance>,
|
||||||
|
/// Packet loss probability
|
||||||
|
loss: Probability,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NetworkStateIpv4Params {
|
||||||
allocation: Ipv4Net,
|
allocation: Ipv4Net,
|
||||||
gateway: Option<NetworkGatewayState>,
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NetworkStateIpv4 {
|
||||||
|
params: NetworkStateIpv4Params,
|
||||||
|
gateway: Option<NetworkStateIpv4Gateway>,
|
||||||
machine_addresses: HashMap<Ipv4Addr, MachineStateId>,
|
machine_addresses: HashMap<Ipv4Addr, MachineStateId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct NetworkStateIpv6 {
|
struct NetworkStateIpv6Params {
|
||||||
allocation: Ipv6Net,
|
allocation: Ipv6Net,
|
||||||
gateway: Option<NetworkGatewayState>,
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NetworkStateIpv6 {
|
||||||
|
params: NetworkStateIpv6Params,
|
||||||
|
gateway: Option<NetworkStateIpv6Gateway>,
|
||||||
machine_addresses: HashMap<Ipv6Addr, MachineStateId>,
|
machine_addresses: HashMap<Ipv6Addr, MachineStateId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct NetworkGatewayState {
|
struct NetworkStateGatewayParams {
|
||||||
translation: config::Translation, // xxx replace with translation state
|
translation: config::Translation,
|
||||||
upnp: bool,
|
upnp: bool,
|
||||||
network: Option<NetworkStateId>,
|
network: Option<NetworkStateId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NetworkStateIpv4Gateway {
|
||||||
|
params: NetworkStateGatewayParams,
|
||||||
|
// xxx add translation state
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NetworkStateIpv6Gateway {
|
||||||
|
params: NetworkStateGatewayParams,
|
||||||
|
// xxx add translation state
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NetworkState {
|
pub struct NetworkState {
|
||||||
unlocked_inner: Arc<NetworkStateUnlockedInner>,
|
unlocked_inner: Arc<NetworkStateUnlockedInner>,
|
||||||
@ -57,79 +86,101 @@ impl NetworkState {
|
|||||||
Self {
|
Self {
|
||||||
unlocked_inner: Arc::new(NetworkStateUnlockedInner { id, opt_name }),
|
unlocked_inner: Arc::new(NetworkStateUnlockedInner { id, opt_name }),
|
||||||
inner: Arc::new(Mutex::new(NetworkStateInner {
|
inner: Arc::new(Mutex::new(NetworkStateInner {
|
||||||
latency: None,
|
generating_blueprint: None,
|
||||||
distance: None,
|
model: NetworkStateModel {
|
||||||
loss: 0.0,
|
latency: None,
|
||||||
|
distance: None,
|
||||||
|
loss: 0.0,
|
||||||
|
},
|
||||||
ipv4: None,
|
ipv4: None,
|
||||||
ipv6: None,
|
ipv6: None,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// let model = network_def.model.clone().unwrap_or_else(|| {
|
pub fn release(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||||
// machine_registry_inner
|
let inner = self.inner.lock();
|
||||||
// .unlocked_inner
|
if let Some(generating_blueprint) = inner.generating_blueprint {
|
||||||
// .config
|
let blueprint_state = machine_registry_inner
|
||||||
// .default_model
|
.blueprint_states_mut()
|
||||||
// .clone()
|
.get_state(generating_blueprint)
|
||||||
// });
|
.expect("must exist");
|
||||||
// let ipv4 = match network_def.ipv4.as_ref() {
|
blueprint_state.on_network_released(self.id());
|
||||||
// Some(ipv4) => Some(NetworkStateIpv4 {
|
}
|
||||||
// allocation: machine_registry_inner.choose_allocation_v4(
|
}
|
||||||
// machine_registry_inner
|
|
||||||
// .unlocked_inner
|
|
||||||
// .config
|
|
||||||
// .allocations
|
|
||||||
// .get(&ipv4.allocation)
|
|
||||||
// .cloned()
|
|
||||||
// .ok_or(MachineRegistryError::InvalidAllocationName)?,
|
|
||||||
// 0,
|
|
||||||
// )?,
|
|
||||||
// gateway: match ipv4.gateway.as_ref() {
|
|
||||||
// Some(v4gw) => Some(NetworkGatewayState {
|
|
||||||
// translation: v4gw.translation,
|
|
||||||
// upnp: v4gw.upnp,
|
|
||||||
// network: v4gw.network.clone().map(|gwname| {
|
|
||||||
// machine_registry_inner
|
|
||||||
// .resolve_to_manager_network
|
|
||||||
// .add(gwname)
|
|
||||||
// }),
|
|
||||||
// }),
|
|
||||||
// None => None,
|
|
||||||
// },
|
|
||||||
// machine_addresses: HashMap::new(),
|
|
||||||
// }),
|
|
||||||
// None => None,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let ipv6 = match network_def.ipv6.as_ref() {
|
pub fn set_model(&self, model: NetworkStateModel) {
|
||||||
// Some(ipv6) => Some(NetworkStateIpv6 {
|
let mut inner = self.inner.lock();
|
||||||
// allocation: machine_registry_inner.choose_allocation_v6(
|
inner.model = model;
|
||||||
// machine_registry_inner
|
}
|
||||||
// .unlocked_inner
|
|
||||||
// .config
|
pub fn set_ipv4(
|
||||||
// .allocations
|
&self,
|
||||||
// .get(&ipv6.allocation)
|
params: NetworkStateIpv4Params,
|
||||||
// .cloned()
|
gateway_params: Option<NetworkStateGatewayParams>,
|
||||||
// .ok_or(MachineRegistryError::InvalidAllocationName)?,
|
) {
|
||||||
// 0,
|
let mut inner = self.inner.lock();
|
||||||
// )?,
|
if inner.ipv4.is_none() {
|
||||||
// gateway: match ipv6.gateway.as_ref() {
|
inner.ipv4 = Some(NetworkStateIpv4 {
|
||||||
// Some(v6gw) => Some(NetworkGatewayState {
|
params,
|
||||||
// translation: v6gw.translation,
|
gateway: None,
|
||||||
// upnp: v6gw.upnp,
|
machine_addresses: HashMap::new(),
|
||||||
// network: v6gw.network.clone().map(|gwname| {
|
});
|
||||||
// machine_registry_inner
|
} else {
|
||||||
// .resolve_to_manager_network
|
inner.ipv4.as_mut().map(|ipv4| {
|
||||||
// .add(gwname)
|
ipv4.params = params;
|
||||||
// }),
|
});
|
||||||
// }),
|
}
|
||||||
// None => None,
|
let ipv4 = inner.ipv4.as_mut().expect("must exist");
|
||||||
// },
|
|
||||||
// machine_addresses: HashMap::new(),
|
if ipv4.gateway.is_some() {
|
||||||
// }),
|
if let Some(gateway_params) = gateway_params {
|
||||||
// None => None,
|
ipv4.gateway.as_mut().expect("must exist").params = gateway_params;
|
||||||
// };
|
} else {
|
||||||
|
ipv4.gateway = None;
|
||||||
|
}
|
||||||
|
} else if let Some(gateway_params) = gateway_params {
|
||||||
|
ipv4.gateway = Some(NetworkStateIpv4Gateway {
|
||||||
|
params: gateway_params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set_ipv6(
|
||||||
|
&self,
|
||||||
|
params: NetworkStateIpv6Params,
|
||||||
|
gateway_params: Option<NetworkStateGatewayParams>,
|
||||||
|
) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if inner.ipv6.is_none() {
|
||||||
|
inner.ipv6 = Some(NetworkStateIpv6 {
|
||||||
|
params,
|
||||||
|
gateway: None,
|
||||||
|
machine_addresses: HashMap::new(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
inner.ipv6.as_mut().map(|ipv6| {
|
||||||
|
ipv6.params = params;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let ipv6 = inner.ipv6.as_mut().expect("must exist");
|
||||||
|
|
||||||
|
if ipv6.gateway.is_some() {
|
||||||
|
if let Some(gateway_params) = gateway_params {
|
||||||
|
ipv6.gateway.as_mut().expect("must exist").params = gateway_params;
|
||||||
|
} else {
|
||||||
|
ipv6.gateway = None;
|
||||||
|
}
|
||||||
|
} else if let Some(gateway_params) = gateway_params {
|
||||||
|
ipv6.gateway = Some(NetworkStateIpv6Gateway {
|
||||||
|
params: gateway_params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_generating_blueprint(&self, generating_blueprint: BlueprintStateId) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.generating_blueprint = Some(generating_blueprint);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_ipv4(&self) -> bool {
|
pub fn is_ipv4(&self) -> bool {
|
||||||
self.inner.lock().ipv4.is_some()
|
self.inner.lock().ipv4.is_some()
|
||||||
@ -143,7 +194,7 @@ impl NetworkState {
|
|||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
let mut can_allocate = false;
|
let mut can_allocate = false;
|
||||||
if let Some(network_state_ipv4) = &inner.ipv4 {
|
if let Some(network_state_ipv4) = &inner.ipv4 {
|
||||||
let hosts_range = network_state_ipv4.allocation.hosts();
|
let hosts_range = network_state_ipv4.params.allocation.hosts();
|
||||||
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
||||||
return Err(MachineRegistryError::NoAllocation);
|
return Err(MachineRegistryError::NoAllocation);
|
||||||
};
|
};
|
||||||
@ -160,7 +211,7 @@ impl NetworkState {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(network_state_ipv6) = &inner.ipv6 {
|
if let Some(network_state_ipv6) = &inner.ipv6 {
|
||||||
let hosts_range = network_state_ipv6.allocation.hosts();
|
let hosts_range = network_state_ipv6.params.allocation.hosts();
|
||||||
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
||||||
return Err(MachineRegistryError::NoAllocation);
|
return Err(MachineRegistryError::NoAllocation);
|
||||||
};
|
};
|
||||||
@ -194,7 +245,7 @@ impl NetworkState {
|
|||||||
// for now we just pick randomly and then increment until we find a free allocation
|
// for now we just pick randomly and then increment until we find a free allocation
|
||||||
// not enough addresses in any address space are allocated to warrant a more efficient algorithm
|
// not enough addresses in any address space are allocated to warrant a more efficient algorithm
|
||||||
|
|
||||||
let hosts_range = network_state_ipv4.allocation.hosts();
|
let hosts_range = network_state_ipv4.params.allocation.hosts();
|
||||||
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
||||||
return Err(MachineRegistryError::NoAllocation);
|
return Err(MachineRegistryError::NoAllocation);
|
||||||
};
|
};
|
||||||
@ -245,8 +296,8 @@ impl NetworkState {
|
|||||||
// Make interface address
|
// Make interface address
|
||||||
let ifaddr = Ifv4Addr {
|
let ifaddr = Ifv4Addr {
|
||||||
ip,
|
ip,
|
||||||
netmask: network_state_ipv4.allocation.netmask(),
|
netmask: network_state_ipv4.params.allocation.netmask(),
|
||||||
broadcast: Some(network_state_ipv4.allocation.broadcast()),
|
broadcast: Some(network_state_ipv4.params.allocation.broadcast()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ifaddr)
|
Ok(ifaddr)
|
||||||
@ -284,7 +335,7 @@ impl NetworkState {
|
|||||||
// for now we just pick randomly and then increment until we find a free allocation
|
// for now we just pick randomly and then increment until we find a free allocation
|
||||||
// not enough addresses in any address space are allocated to warrant a more efficient algorithm
|
// not enough addresses in any address space are allocated to warrant a more efficient algorithm
|
||||||
|
|
||||||
let hosts_range = network_state_ipv6.allocation.hosts();
|
let hosts_range = network_state_ipv6.params.allocation.hosts();
|
||||||
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
||||||
return Err(MachineRegistryError::NoAllocation);
|
return Err(MachineRegistryError::NoAllocation);
|
||||||
};
|
};
|
||||||
@ -335,8 +386,8 @@ impl NetworkState {
|
|||||||
// Make interface address
|
// Make interface address
|
||||||
let ifaddr = Ifv6Addr {
|
let ifaddr = Ifv6Addr {
|
||||||
ip,
|
ip,
|
||||||
netmask: network_state_ipv6.allocation.netmask(),
|
netmask: network_state_ipv6.params.allocation.netmask(),
|
||||||
broadcast: Some(network_state_ipv6.allocation.broadcast()),
|
broadcast: Some(network_state_ipv6.params.allocation.broadcast()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ifaddr)
|
Ok(ifaddr)
|
||||||
|
@ -147,7 +147,7 @@ impl<S: State> StateAllocator<S> {
|
|||||||
|
|
||||||
// Take the state out of the slot and ensure the state slot isn't detached already
|
// Take the state out of the slot and ensure the state slot isn't detached already
|
||||||
let Some(state) = opt_state.take() else {
|
let Some(state) = opt_state.take() else {
|
||||||
return Err(MachineRegistryError::AlreadyDetached);
|
return Err(MachineRegistryError::NotAttached);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Release the name if it exists
|
// Release the name if it exists
|
||||||
@ -162,13 +162,15 @@ impl<S: State> StateAllocator<S> {
|
|||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_state(&self, id: StateId<S>) -> MachineRegistryResult<Option<S>> {
|
pub fn get_state(&self, id: StateId<S>) -> MachineRegistryResult<S> {
|
||||||
// Get the allocator slot
|
// Get the allocator slot
|
||||||
let Some(opt_state) = self.state_by_id.get(&id.0).cloned() else {
|
let Some(opt_state) = self.state_by_id.get(&id.0).cloned() else {
|
||||||
return Err(MachineRegistryError::InvalidId);
|
return Err(MachineRegistryError::InvalidId);
|
||||||
};
|
};
|
||||||
|
let Some(state) = opt_state else {
|
||||||
Ok(opt_state)
|
return Err(MachineRegistryError::NotAttached);
|
||||||
|
};
|
||||||
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_state_by_name(&self, name: &String) -> Option<S> {
|
pub fn get_state_by_name(&self, name: &String) -> Option<S> {
|
||||||
|
@ -22,6 +22,12 @@ enum LocationsList {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum BlueprintAvailability {
|
||||||
|
Existing(NetworkState),
|
||||||
|
Generate(BlueprintState),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct TemplateStateInner {
|
struct TemplateStateInner {
|
||||||
limit_machine_count: Option<usize>,
|
limit_machine_count: Option<usize>,
|
||||||
@ -29,6 +35,7 @@ struct TemplateStateInner {
|
|||||||
locations_list: Option<LocationsList>,
|
locations_list: Option<LocationsList>,
|
||||||
machines: HashSet<MachineStateId>,
|
machines: HashSet<MachineStateId>,
|
||||||
machines_per_network: HashMap<NetworkStateId, PerNetworkInfo>,
|
machines_per_network: HashMap<NetworkStateId, PerNetworkInfo>,
|
||||||
|
disable_capabilities: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -49,10 +56,16 @@ impl TemplateState {
|
|||||||
locations_list: None,
|
locations_list: None,
|
||||||
machines: HashSet::new(),
|
machines: HashSet::new(),
|
||||||
machines_per_network: HashMap::new(),
|
machines_per_network: HashMap::new(),
|
||||||
|
disable_capabilities: Vec::new(),
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_disable_capabilities(&self, disable_capabilities: Vec<String>) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.disable_capabilities = disable_capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_networks_list(&self, networks: WeightedList<NetworkStateId>) {
|
pub fn set_networks_list(&self, networks: WeightedList<NetworkStateId>) {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.locations_list = Some(LocationsList::Networks { networks })
|
inner.locations_list = Some(LocationsList::Networks { networks })
|
||||||
@ -107,38 +120,35 @@ impl TemplateState {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
xxx should this be sensitive to already generated blueprint networks?
|
|
||||||
|
|
||||||
fn is_blueprint_available_inner(
|
fn is_blueprint_available_inner(
|
||||||
inner: &TemplateStateInner,
|
inner: &TemplateStateInner,
|
||||||
machine_registry_inner: &MachineRegistryInner,
|
machine_registry_inner: &MachineRegistryInner,
|
||||||
blueprint_state: BlueprintState,
|
blueprint_state: BlueprintState,
|
||||||
) -> MachineRegistryResult<Availability<NetworkStateId>> {
|
) -> MachineRegistryResult<Option<BlueprintAvailability>> {
|
||||||
// See if the networks generated from this blueprint so far have availability
|
// See if the networks generated from this blueprint so far have availability
|
||||||
// in this template
|
// in this template
|
||||||
if let Some(available_network_id) = blueprint_state.for_each_network_id(|id| {
|
if let Some(available_network_state) = blueprint_state.for_each_network_id(|id| {
|
||||||
// Check the network's availability
|
// Check the network's availability
|
||||||
let network_state = machine_registry_inner
|
let network_state = machine_registry_inner.network_states().get_state(id)?;
|
||||||
.network_states()
|
if Self::is_network_available_inner(inner, network_state.clone())? {
|
||||||
.get_state(id)?
|
|
||||||
.expect("must exist");
|
|
||||||
if Self::is_network_available_inner(inner, network_state)? {
|
|
||||||
// We found one
|
// We found one
|
||||||
return Ok(Some(id));
|
return Ok(Some(network_state));
|
||||||
}
|
}
|
||||||
// Try next network
|
// Try next network
|
||||||
Ok(None)
|
Ok(None)
|
||||||
})? {
|
})? {
|
||||||
// We found a usable network
|
// We found a usable network
|
||||||
return Ok(Availability::Existing(available_network_id));
|
return Ok(Some(BlueprintAvailability::Existing(
|
||||||
|
available_network_state,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the blueprint is active, it is available because it can make a new network
|
// If the blueprint is active, it is available because it can make a new network
|
||||||
if blueprint_state.is_active()? {
|
if blueprint_state.is_active()? {
|
||||||
return Ok(Availability::New);
|
return Ok(Some(BlueprintAvailability::Generate(blueprint_state)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Availability::None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_active(
|
pub fn is_active(
|
||||||
@ -163,12 +173,9 @@ xxx should this be sensitive to already generated blueprint networks?
|
|||||||
// Filter the weighted list of networks to those that are still active and or not yet started
|
// Filter the weighted list of networks to those that are still active and or not yet started
|
||||||
if networks
|
if networks
|
||||||
.try_filter(|id| {
|
.try_filter(|id| {
|
||||||
machine_registry_inner
|
let network_state =
|
||||||
.network_states()
|
machine_registry_inner.network_states().get_state(*id)?;
|
||||||
.get_state(*id)?
|
Self::is_network_available_inner(&*inner, network_state)
|
||||||
.clone()
|
|
||||||
.map(|ns| Self::is_network_available_inner(&*inner, ns))
|
|
||||||
.unwrap_or(Ok(true))
|
|
||||||
})?
|
})?
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
@ -179,19 +186,15 @@ xxx should this be sensitive to already generated blueprint networks?
|
|||||||
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
||||||
if blueprints
|
if blueprints
|
||||||
.try_filter(|id| {
|
.try_filter(|id| {
|
||||||
machine_registry_inner
|
let blueprint_state =
|
||||||
.blueprint_states()
|
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||||
.get_state(*id)?
|
|
||||||
.clone()
|
Self::is_blueprint_available_inner(
|
||||||
.map(|bs| {
|
&*inner,
|
||||||
Self::is_blueprint_available_inner(
|
machine_registry_inner,
|
||||||
&*inner,
|
blueprint_state,
|
||||||
machine_registry_inner,
|
)
|
||||||
bs,
|
.map(|x| x.is_some())
|
||||||
)
|
|
||||||
.map(|x| !matches!(x, Availability::None))
|
|
||||||
})
|
|
||||||
.unwrap_or(Ok(true))
|
|
||||||
})?
|
})?
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
@ -225,90 +228,115 @@ xxx should this be sensitive to already generated blueprint networks?
|
|||||||
let network_state = match locations_list {
|
let network_state = match locations_list {
|
||||||
LocationsList::Networks { networks } => {
|
LocationsList::Networks { networks } => {
|
||||||
// Filter the weighted list of networks to those that are still active and or not yet started
|
// Filter the weighted list of networks to those that are still active and or not yet started
|
||||||
let Some(active_networks) = networks.try_filter(|id| {
|
let Some(available_networks) = networks.try_filter_map(|id| {
|
||||||
machine_registry_inner
|
let network_state = machine_registry_inner.network_states().get_state(*id)?;
|
||||||
.network_states()
|
if Self::is_network_available_inner(&*inner, network_state.clone())? {
|
||||||
.get_state(*id)?
|
Ok(Some(network_state))
|
||||||
.clone()
|
} else {
|
||||||
.map(|ns| Self::is_network_available_inner(&*inner, ns))
|
Ok(None)
|
||||||
.unwrap_or(Ok(true))
|
}
|
||||||
})?
|
})?
|
||||||
else {
|
else {
|
||||||
return Err(MachineRegistryError::NetworkComplete);
|
return Err(MachineRegistryError::NetworkComplete);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Weighted choice of network now that we have a candidate list
|
// Weighted choice of network now that we have a candidate list
|
||||||
let network_id = machine_registry_inner
|
|
||||||
.srng()
|
|
||||||
.weighted_choice(&active_networks);
|
|
||||||
|
|
||||||
// Get the fixed network
|
|
||||||
let network_state = machine_registry_inner
|
let network_state = machine_registry_inner
|
||||||
.network_states()
|
.srng()
|
||||||
.get_state(*network_id)?
|
.weighted_choice(&available_networks);
|
||||||
.expect("must exist");
|
|
||||||
|
|
||||||
// Return network state to use
|
// Return network state to use
|
||||||
network_state
|
network_state.clone()
|
||||||
}
|
}
|
||||||
LocationsList::Blueprints { blueprints } => {
|
LocationsList::Blueprints { blueprints } => {
|
||||||
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
||||||
let Some(active_blueprints) = blueprints.try_filter(|id| {
|
let Some(available_blueprints) = blueprints.try_filter_map(|id| {
|
||||||
machine_registry_inner
|
let blueprint_state =
|
||||||
.blueprint_states()
|
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||||
.get_state(*id)?
|
|
||||||
.clone()
|
Self::is_blueprint_available_inner(
|
||||||
.map(|bs| {
|
&*inner,
|
||||||
Self::is_blueprint_available_inner(&*inner, machine_registry_inner, bs)
|
machine_registry_inner,
|
||||||
.map(|x| !matches!(x, Availability::None))
|
blueprint_state,
|
||||||
})
|
)
|
||||||
.unwrap_or(Ok(true))
|
|
||||||
})?
|
})?
|
||||||
else {
|
else {
|
||||||
return Err(MachineRegistryError::BlueprintComplete);
|
return Err(MachineRegistryError::BlueprintComplete);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Weighted choice of blueprint now that we have a candidate list
|
// Weighted choice of blueprint now that we have a candidate list
|
||||||
let blueprint_id = machine_registry_inner
|
match machine_registry_inner
|
||||||
.srng()
|
.srng()
|
||||||
.weighted_choice(&active_blueprints);
|
.weighted_choice(&available_blueprints)
|
||||||
|
{
|
||||||
xxx do not always generate... use most recent network for this blueprint in this template.
|
BlueprintAvailability::Existing(network_state) => network_state.clone(),
|
||||||
|
BlueprintAvailability::Generate(blueprint_state) => {
|
||||||
// Instantiate a blueprint network
|
blueprint_state.generate(machine_registry_inner)?
|
||||||
let blueprint_state = machine_registry_inner
|
}
|
||||||
.blueprint_states()
|
}
|
||||||
.get_state(*blueprint_id)?
|
|
||||||
.expect("must exist");
|
|
||||||
|
|
||||||
blueprint_state.generate(machine_registry_inner)?
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate a machine id
|
// Allocate a machine id
|
||||||
let machine_id = machine_registry_inner.machine_states().allocate_id();
|
let machine_state_id = machine_registry_inner.machine_states_mut().allocate_id();
|
||||||
|
|
||||||
// Create an anonymous machine state
|
// Create an anonymous machine state
|
||||||
let mut machine_state = MachineState::new(machine_id, None);
|
let machine_state = MachineState::new(machine_state_id, None);
|
||||||
|
|
||||||
// Build out the machine state from the template
|
if let Err(e) = (|| {
|
||||||
//inner.
|
// Build out the machine state from the template
|
||||||
|
machine_state.set_disable_capabilities(inner.disable_capabilities.clone());
|
||||||
|
machine_state.set_bootstrap(false);
|
||||||
|
|
||||||
|
// Make the default route interface
|
||||||
|
let vin0 = machine_state.allocate_interface(network_state.id(), None, None)?;
|
||||||
|
if network_state.is_ipv4() {
|
||||||
|
machine_state.allocate_address_ipv4(machine_registry_inner, &vin0, None, None)?;
|
||||||
|
}
|
||||||
|
if network_state.is_ipv6() {
|
||||||
|
machine_state.allocate_address_ipv6(machine_registry_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_states_mut()
|
||||||
|
.release_id(machine_state_id);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
// Attach the state to the id
|
// Attach the state to the id
|
||||||
machine_registry_inner
|
machine_registry_inner
|
||||||
.machine_states()
|
.machine_states_mut()
|
||||||
.attach_state(machine_state.clone());
|
.attach_state(machine_state.clone());
|
||||||
|
|
||||||
// Record the newly instantiated machine
|
// Record the newly instantiated machine
|
||||||
inner.machines.insert(machine_id);
|
inner.machines.insert(machine_state_id);
|
||||||
let per_network_info = inner.machines_per_network.entry(network_state).or_insert_with(|| {
|
let limit_machines_per_network = inner.limit_machines_per_network.clone();
|
||||||
let limit_machine_count = inner.limit_machines_per_network.map(|wl| machine_registry_inner.srng().weighted_choice(&wl)).copied();
|
let per_network_info = inner
|
||||||
PerNetworkInfo{ limit_machine_count, machines: HashSet::new() }
|
.machines_per_network
|
||||||
});
|
.entry(network_state.id())
|
||||||
per_network_info.machines.insert(machine_id);
|
.or_insert_with(|| {
|
||||||
|
let limit_machine_count = limit_machines_per_network
|
||||||
|
.map(|wl| machine_registry_inner.srng().weighted_choice(&wl).clone());
|
||||||
|
PerNetworkInfo {
|
||||||
|
limit_machine_count,
|
||||||
|
machines: HashSet::new(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
per_network_info.machines.insert(machine_state_id);
|
||||||
|
|
||||||
Ok(machine_state)
|
Ok(machine_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_machine_released(&self, machine_state_id: MachineStateId) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.machines.remove(&machine_state_id);
|
||||||
|
for (_network_id, pni) in &mut inner.machines_per_network {
|
||||||
|
pni.machines.remove(&machine_state_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State for TemplateState {
|
impl State for TemplateState {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user