mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-12-24 14:59:31 -05:00
[skip ci] network and blueprint code
This commit is contained in:
parent
826f1cc782
commit
f09b367d05
@ -1,5 +1,3 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -137,11 +135,9 @@ impl MachineRegistryInner {
|
||||
self.allocated_machines.remove(&id);
|
||||
} else {
|
||||
// Was a templated machine, so remove the machine state
|
||||
let Some(machine_state) = self.machine_states().get_state(id)? else {
|
||||
return Err(MachineRegistryError::InvalidId);
|
||||
};
|
||||
let machine_state = self.machine_states().get_state(id)?;
|
||||
machine_state.release(self);
|
||||
self.machine_states().release_id(id)?;
|
||||
self.machine_states_mut().release_id(id)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -150,19 +146,35 @@ impl MachineRegistryInner {
|
||||
///////////////////////////////////////////////////////////
|
||||
/// 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
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ mod machine_registry_inner;
|
||||
mod state;
|
||||
|
||||
use super::*;
|
||||
use ipnet::*;
|
||||
|
||||
use address_pool::*;
|
||||
use machine_registry_inner::*;
|
||||
@ -23,7 +22,7 @@ pub enum MachineRegistryError {
|
||||
InvalidId,
|
||||
InvalidName,
|
||||
AlreadyAttached,
|
||||
AlreadyDetached,
|
||||
NotAttached,
|
||||
DuplicateName,
|
||||
ProfileComplete,
|
||||
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,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
struct BlueprintStateInner {
|
||||
limit_network_count: Option<usize>,
|
||||
networks: Vec<NetworkStateId>,
|
||||
model: Option<WeightedList<String>>,
|
||||
ipv4: Option<BlueprintStateIpv4>,
|
||||
ipv6: Option<BlueprintStateIpv6>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -27,6 +73,9 @@ impl BlueprintState {
|
||||
inner: Arc::new(Mutex::new(BlueprintStateInner {
|
||||
limit_network_count: None,
|
||||
networks: Vec::new(),
|
||||
model: None,
|
||||
ipv4: None,
|
||||
ipv6: None,
|
||||
})),
|
||||
})
|
||||
}
|
||||
@ -36,6 +85,73 @@ impl BlueprintState {
|
||||
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> {
|
||||
let inner = self.inner.lock();
|
||||
|
||||
@ -49,16 +165,77 @@ impl BlueprintState {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn generate(
|
||||
&self,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
) -> MachineRegistryResult<NetworkState> {
|
||||
fn generate_model_inner(
|
||||
inner: &mut BlueprintStateInner,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
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
|
||||
F: FnMut(NetworkStateId) -> MachineRegistryResult<Option<R>>,
|
||||
F: Fn(NetworkStateId) -> MachineRegistryResult<Option<R>>,
|
||||
{
|
||||
let inner = self.inner.lock();
|
||||
for network_id in &inner.networks {
|
||||
@ -68,6 +245,16 @@ impl BlueprintState {
|
||||
}
|
||||
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 {
|
||||
|
@ -2,8 +2,14 @@ use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MachineStateInner {
|
||||
/// The template generating this machine
|
||||
generating_template: Option<TemplateStateId>,
|
||||
/// The current network interfaces definition
|
||||
interfaces: HashMap<String, MachineStateInterface>,
|
||||
/// Capabilities to disable on this machine
|
||||
disable_capabilities: Vec<String>,
|
||||
/// If this machine is a bootstrap
|
||||
bootstrap: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -36,19 +42,45 @@ impl MachineState {
|
||||
Self {
|
||||
unlocked_inner: Arc::new(MachineStateUnlockedInner { id, opt_name }),
|
||||
inner: Arc::new(Mutex::new(MachineStateInner {
|
||||
generating_template: None,
|
||||
interfaces: HashMap::new(),
|
||||
disable_capabilities: Vec::new(),
|
||||
bootstrap: false,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||
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 {
|
||||
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 {
|
||||
let mut inum = 0usize;
|
||||
loop {
|
||||
@ -111,12 +143,9 @@ impl MachineState {
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let Some(network_state) = machine_registry_inner
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NetworkNotFound);
|
||||
};
|
||||
.get_state(intf.network_id)?;
|
||||
|
||||
// Allocate interface address
|
||||
let is_dynamic = opt_address.is_none();
|
||||
@ -151,12 +180,9 @@ impl MachineState {
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let Some(network_state) = machine_registry_inner
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NetworkNotFound);
|
||||
};
|
||||
.get_state(intf.network_id)?;
|
||||
|
||||
// Allocate interface address
|
||||
let is_dynamic = opt_address.is_none();
|
||||
@ -190,12 +216,9 @@ impl MachineState {
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let Some(network_state) = machine_registry_inner
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NetworkNotFound);
|
||||
};
|
||||
.get_state(intf.network_id)?;
|
||||
|
||||
// Release the address from the network
|
||||
match address {
|
||||
@ -230,12 +253,9 @@ impl MachineState {
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let Some(network_state) = machine_registry_inner
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NetworkNotFound);
|
||||
};
|
||||
.get_state(intf.network_id)?;
|
||||
|
||||
// Release the addresses from the network
|
||||
for addr in &intf.network_interface.addrs {
|
||||
|
@ -1,4 +1,3 @@
|
||||
mod availability;
|
||||
mod blueprint_state;
|
||||
mod machine_state;
|
||||
mod network_state;
|
||||
@ -10,7 +9,6 @@ use std::marker::PhantomData;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub use availability::*;
|
||||
pub use blueprint_state::*;
|
||||
pub use machine_state::*;
|
||||
pub use network_state::*;
|
||||
|
@ -11,12 +11,10 @@ struct NetworkStateUnlockedInner {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateInner {
|
||||
/// Network latency distribution
|
||||
latency: Option<config::Distribution>,
|
||||
/// Distance simulation metric
|
||||
distance: Option<config::Distance>,
|
||||
/// Packet loss probability
|
||||
loss: Probability,
|
||||
/// The blueprint generating this network
|
||||
generating_blueprint: Option<BlueprintStateId>,
|
||||
/// Model for this network
|
||||
model: NetworkStateModel,
|
||||
/// IPv4 state if it is enabled
|
||||
ipv4: Option<NetworkStateIpv4>,
|
||||
/// IPv6 state if it is enabled
|
||||
@ -24,26 +22,57 @@ struct NetworkStateInner {
|
||||
}
|
||||
|
||||
#[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,
|
||||
gateway: Option<NetworkGatewayState>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateIpv4 {
|
||||
params: NetworkStateIpv4Params,
|
||||
gateway: Option<NetworkStateIpv4Gateway>,
|
||||
machine_addresses: HashMap<Ipv4Addr, MachineStateId>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateIpv6 {
|
||||
struct NetworkStateIpv6Params {
|
||||
allocation: Ipv6Net,
|
||||
gateway: Option<NetworkGatewayState>,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateIpv6 {
|
||||
params: NetworkStateIpv6Params,
|
||||
gateway: Option<NetworkStateIpv6Gateway>,
|
||||
machine_addresses: HashMap<Ipv6Addr, MachineStateId>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkGatewayState {
|
||||
translation: config::Translation, // xxx replace with translation state
|
||||
struct NetworkStateGatewayParams {
|
||||
translation: config::Translation,
|
||||
upnp: bool,
|
||||
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)]
|
||||
pub struct NetworkState {
|
||||
unlocked_inner: Arc<NetworkStateUnlockedInner>,
|
||||
@ -57,79 +86,101 @@ impl NetworkState {
|
||||
Self {
|
||||
unlocked_inner: Arc::new(NetworkStateUnlockedInner { id, opt_name }),
|
||||
inner: Arc::new(Mutex::new(NetworkStateInner {
|
||||
latency: None,
|
||||
distance: None,
|
||||
loss: 0.0,
|
||||
generating_blueprint: None,
|
||||
model: NetworkStateModel {
|
||||
latency: None,
|
||||
distance: None,
|
||||
loss: 0.0,
|
||||
},
|
||||
ipv4: None,
|
||||
ipv6: None,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
// let model = network_def.model.clone().unwrap_or_else(|| {
|
||||
// machine_registry_inner
|
||||
// .unlocked_inner
|
||||
// .config
|
||||
// .default_model
|
||||
// .clone()
|
||||
// });
|
||||
// let ipv4 = match network_def.ipv4.as_ref() {
|
||||
// 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,
|
||||
// };
|
||||
pub fn release(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||
let inner = self.inner.lock();
|
||||
if let Some(generating_blueprint) = inner.generating_blueprint {
|
||||
let blueprint_state = machine_registry_inner
|
||||
.blueprint_states_mut()
|
||||
.get_state(generating_blueprint)
|
||||
.expect("must exist");
|
||||
blueprint_state.on_network_released(self.id());
|
||||
}
|
||||
}
|
||||
|
||||
// let ipv6 = match network_def.ipv6.as_ref() {
|
||||
// Some(ipv6) => Some(NetworkStateIpv6 {
|
||||
// allocation: machine_registry_inner.choose_allocation_v6(
|
||||
// machine_registry_inner
|
||||
// .unlocked_inner
|
||||
// .config
|
||||
// .allocations
|
||||
// .get(&ipv6.allocation)
|
||||
// .cloned()
|
||||
// .ok_or(MachineRegistryError::InvalidAllocationName)?,
|
||||
// 0,
|
||||
// )?,
|
||||
// gateway: match ipv6.gateway.as_ref() {
|
||||
// Some(v6gw) => Some(NetworkGatewayState {
|
||||
// translation: v6gw.translation,
|
||||
// upnp: v6gw.upnp,
|
||||
// network: v6gw.network.clone().map(|gwname| {
|
||||
// machine_registry_inner
|
||||
// .resolve_to_manager_network
|
||||
// .add(gwname)
|
||||
// }),
|
||||
// }),
|
||||
// None => None,
|
||||
// },
|
||||
// machine_addresses: HashMap::new(),
|
||||
// }),
|
||||
// None => None,
|
||||
// };
|
||||
pub fn set_model(&self, model: NetworkStateModel) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.model = model;
|
||||
}
|
||||
|
||||
pub fn set_ipv4(
|
||||
&self,
|
||||
params: NetworkStateIpv4Params,
|
||||
gateway_params: Option<NetworkStateGatewayParams>,
|
||||
) {
|
||||
let mut inner = self.inner.lock();
|
||||
if inner.ipv4.is_none() {
|
||||
inner.ipv4 = Some(NetworkStateIpv4 {
|
||||
params,
|
||||
gateway: None,
|
||||
machine_addresses: HashMap::new(),
|
||||
});
|
||||
} 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(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 {
|
||||
self.inner.lock().ipv4.is_some()
|
||||
@ -143,7 +194,7 @@ impl NetworkState {
|
||||
let inner = self.inner.lock();
|
||||
let mut can_allocate = false;
|
||||
if let Some(network_state_ipv4) = &inner.ipv4 {
|
||||
let hosts_range = network_state_ipv4.allocation.hosts();
|
||||
let hosts_range = network_state_ipv4.params.allocation.hosts();
|
||||
let Some(first_host) = std::iter::Iterator::min(hosts_range) else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
@ -160,7 +211,7 @@ impl NetworkState {
|
||||
}
|
||||
};
|
||||
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 {
|
||||
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
|
||||
// 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 {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
@ -245,8 +296,8 @@ impl NetworkState {
|
||||
// Make interface address
|
||||
let ifaddr = Ifv4Addr {
|
||||
ip,
|
||||
netmask: network_state_ipv4.allocation.netmask(),
|
||||
broadcast: Some(network_state_ipv4.allocation.broadcast()),
|
||||
netmask: network_state_ipv4.params.allocation.netmask(),
|
||||
broadcast: Some(network_state_ipv4.params.allocation.broadcast()),
|
||||
};
|
||||
|
||||
Ok(ifaddr)
|
||||
@ -284,7 +335,7 @@ impl NetworkState {
|
||||
// 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
|
||||
|
||||
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 {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
@ -335,8 +386,8 @@ impl NetworkState {
|
||||
// Make interface address
|
||||
let ifaddr = Ifv6Addr {
|
||||
ip,
|
||||
netmask: network_state_ipv6.allocation.netmask(),
|
||||
broadcast: Some(network_state_ipv6.allocation.broadcast()),
|
||||
netmask: network_state_ipv6.params.allocation.netmask(),
|
||||
broadcast: Some(network_state_ipv6.params.allocation.broadcast()),
|
||||
};
|
||||
|
||||
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
|
||||
let Some(state) = opt_state.take() else {
|
||||
return Err(MachineRegistryError::AlreadyDetached);
|
||||
return Err(MachineRegistryError::NotAttached);
|
||||
};
|
||||
|
||||
// Release the name if it exists
|
||||
@ -162,13 +162,15 @@ impl<S: State> StateAllocator<S> {
|
||||
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
|
||||
let Some(opt_state) = self.state_by_id.get(&id.0).cloned() else {
|
||||
return Err(MachineRegistryError::InvalidId);
|
||||
};
|
||||
|
||||
Ok(opt_state)
|
||||
let Some(state) = opt_state else {
|
||||
return Err(MachineRegistryError::NotAttached);
|
||||
};
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
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)]
|
||||
struct TemplateStateInner {
|
||||
limit_machine_count: Option<usize>,
|
||||
@ -29,6 +35,7 @@ struct TemplateStateInner {
|
||||
locations_list: Option<LocationsList>,
|
||||
machines: HashSet<MachineStateId>,
|
||||
machines_per_network: HashMap<NetworkStateId, PerNetworkInfo>,
|
||||
disable_capabilities: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -49,10 +56,16 @@ impl TemplateState {
|
||||
locations_list: None,
|
||||
machines: HashSet::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>) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.locations_list = Some(LocationsList::Networks { networks })
|
||||
@ -107,38 +120,35 @@ impl TemplateState {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
xxx should this be sensitive to already generated blueprint networks?
|
||||
|
||||
fn is_blueprint_available_inner(
|
||||
inner: &TemplateStateInner,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
blueprint_state: BlueprintState,
|
||||
) -> MachineRegistryResult<Availability<NetworkStateId>> {
|
||||
) -> MachineRegistryResult<Option<BlueprintAvailability>> {
|
||||
// See if the networks generated from this blueprint so far have availability
|
||||
// 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
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(id)?
|
||||
.expect("must exist");
|
||||
if Self::is_network_available_inner(inner, network_state)? {
|
||||
let network_state = machine_registry_inner.network_states().get_state(id)?;
|
||||
if Self::is_network_available_inner(inner, network_state.clone())? {
|
||||
// We found one
|
||||
return Ok(Some(id));
|
||||
return Ok(Some(network_state));
|
||||
}
|
||||
// Try next network
|
||||
Ok(None)
|
||||
})? {
|
||||
// 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 blueprint_state.is_active()? {
|
||||
return Ok(Availability::New);
|
||||
return Ok(Some(BlueprintAvailability::Generate(blueprint_state)));
|
||||
}
|
||||
|
||||
Ok(Availability::None)
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
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
|
||||
if networks
|
||||
.try_filter(|id| {
|
||||
machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(*id)?
|
||||
.clone()
|
||||
.map(|ns| Self::is_network_available_inner(&*inner, ns))
|
||||
.unwrap_or(Ok(true))
|
||||
let network_state =
|
||||
machine_registry_inner.network_states().get_state(*id)?;
|
||||
Self::is_network_available_inner(&*inner, network_state)
|
||||
})?
|
||||
.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
|
||||
if blueprints
|
||||
.try_filter(|id| {
|
||||
machine_registry_inner
|
||||
.blueprint_states()
|
||||
.get_state(*id)?
|
||||
.clone()
|
||||
.map(|bs| {
|
||||
Self::is_blueprint_available_inner(
|
||||
&*inner,
|
||||
machine_registry_inner,
|
||||
bs,
|
||||
)
|
||||
.map(|x| !matches!(x, Availability::None))
|
||||
})
|
||||
.unwrap_or(Ok(true))
|
||||
let blueprint_state =
|
||||
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||
|
||||
Self::is_blueprint_available_inner(
|
||||
&*inner,
|
||||
machine_registry_inner,
|
||||
blueprint_state,
|
||||
)
|
||||
.map(|x| x.is_some())
|
||||
})?
|
||||
.is_none()
|
||||
{
|
||||
@ -225,90 +228,115 @@ xxx should this be sensitive to already generated blueprint networks?
|
||||
let network_state = match locations_list {
|
||||
LocationsList::Networks { networks } => {
|
||||
// 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| {
|
||||
machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(*id)?
|
||||
.clone()
|
||||
.map(|ns| Self::is_network_available_inner(&*inner, ns))
|
||||
.unwrap_or(Ok(true))
|
||||
let Some(available_networks) = networks.try_filter_map(|id| {
|
||||
let network_state = machine_registry_inner.network_states().get_state(*id)?;
|
||||
if Self::is_network_available_inner(&*inner, network_state.clone())? {
|
||||
Ok(Some(network_state))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::NetworkComplete);
|
||||
};
|
||||
|
||||
// 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
|
||||
.network_states()
|
||||
.get_state(*network_id)?
|
||||
.expect("must exist");
|
||||
.srng()
|
||||
.weighted_choice(&available_networks);
|
||||
|
||||
// Return network state to use
|
||||
network_state
|
||||
network_state.clone()
|
||||
}
|
||||
LocationsList::Blueprints { blueprints } => {
|
||||
// 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| {
|
||||
machine_registry_inner
|
||||
.blueprint_states()
|
||||
.get_state(*id)?
|
||||
.clone()
|
||||
.map(|bs| {
|
||||
Self::is_blueprint_available_inner(&*inner, machine_registry_inner, bs)
|
||||
.map(|x| !matches!(x, Availability::None))
|
||||
})
|
||||
.unwrap_or(Ok(true))
|
||||
let Some(available_blueprints) = blueprints.try_filter_map(|id| {
|
||||
let blueprint_state =
|
||||
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||
|
||||
Self::is_blueprint_available_inner(
|
||||
&*inner,
|
||||
machine_registry_inner,
|
||||
blueprint_state,
|
||||
)
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::BlueprintComplete);
|
||||
};
|
||||
|
||||
// Weighted choice of blueprint now that we have a candidate list
|
||||
let blueprint_id = machine_registry_inner
|
||||
match machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice(&active_blueprints);
|
||||
|
||||
xxx do not always generate... use most recent network for this blueprint in this template.
|
||||
|
||||
// Instantiate a blueprint network
|
||||
let blueprint_state = machine_registry_inner
|
||||
.blueprint_states()
|
||||
.get_state(*blueprint_id)?
|
||||
.expect("must exist");
|
||||
|
||||
blueprint_state.generate(machine_registry_inner)?
|
||||
.weighted_choice(&available_blueprints)
|
||||
{
|
||||
BlueprintAvailability::Existing(network_state) => network_state.clone(),
|
||||
BlueprintAvailability::Generate(blueprint_state) => {
|
||||
blueprint_state.generate(machine_registry_inner)?
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
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
|
||||
//inner.
|
||||
if let Err(e) = (|| {
|
||||
// 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
|
||||
machine_registry_inner
|
||||
.machine_states()
|
||||
.machine_states_mut()
|
||||
.attach_state(machine_state.clone());
|
||||
|
||||
// Record the newly instantiated machine
|
||||
inner.machines.insert(machine_id);
|
||||
let per_network_info = inner.machines_per_network.entry(network_state).or_insert_with(|| {
|
||||
let limit_machine_count = inner.limit_machines_per_network.map(|wl| machine_registry_inner.srng().weighted_choice(&wl)).copied();
|
||||
PerNetworkInfo{ limit_machine_count, machines: HashSet::new() }
|
||||
});
|
||||
per_network_info.machines.insert(machine_id);
|
||||
inner.machines.insert(machine_state_id);
|
||||
let limit_machines_per_network = inner.limit_machines_per_network.clone();
|
||||
let per_network_info = inner
|
||||
.machines_per_network
|
||||
.entry(network_state.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)
|
||||
}
|
||||
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user