[skip ci] checkpoint

This commit is contained in:
Christien Rioux 2025-01-03 20:45:38 -05:00
parent c361dce995
commit 10534b5bb7
3 changed files with 320 additions and 335 deletions

View File

@ -1,7 +1,7 @@
use super::*;
/// Locations where a machine can be instantiated
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum MachineLocationsList {
Networks {
networks: WeightedList<NetworkStateId>,

View File

@ -156,25 +156,26 @@ impl NetworkState {
}
pub fn clear_ipv4(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
) -> MachineRegistryResult<()> {
let Some(ipv4) = inner.ipv4.as_mut() else {
let Some(ipv4) = self.fields.ipv4.clone() else {
return Ok(());
};
inner.address_pool.clear_ipv4(|_n, t| match t {
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,
OwnerTag::Network(nsid) => *nsid != self.id(),
OwnerTag::Gateway(nsid) => *nsid != self.id(),
})?;
// 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 {
if gateway.params.external_network != self.id() {
// Get the external network state
let external_network_state = machine_registry_inner
let mut external_network_state = machine_registry_inner
.network_states()
.get_state(gateway.params.external_network)
.expect("must succeed");
@ -183,35 +184,47 @@ impl NetworkState {
external_network_state
.release_address_v4(gateway.external_interface_address.ip)
.expect("must succeed");
// Update external network
machine_registry_inner
.network_states_mut()
.set_state(external_network_state);
}
}
inner.ipv4 = None;
// Update fields
self.fields = Arc::new(NetworkStateFields {
ipv4: None,
address_pool,
..(*self.fields).clone()
});
Ok(())
}
pub fn set_ipv4(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
params: NetworkStateIpv4Params,
gateway_params: Option<NetworkStateIpv4GatewayParams>,
) -> MachineRegistryResult<()> {
Self::clear_ipv4_inner(self.id(), &mut *inner, machine_registry_inner)?;
self.clear_ipv4(machine_registry_inner)?;
inner.address_pool.add_scope_v4(params.allocation);
let mut address_pool = self.fields.address_pool.clone();
address_pool.add_scope_v4(params.allocation);
let gateway = match gateway_params {
Some(gateway_params) => {
// Allocate or reserve an internal network address for the gateway
let internal_address =
if let Some(internal_address) = gateway_params.internal_address {
inner.address_pool.reserve_allocation_v4(
address_pool.reserve_allocation_v4(
Ipv4Net::new(internal_address, 32).expect("must succeed"),
Some(OwnerTag::Gateway(self.id())),
)?;
internal_address
} else {
let Some(internal_address) = inner.address_pool.allocate_random_v4(
let Some(internal_address) = address_pool.allocate_random_v4(
machine_registry_inner.srng(),
32,
OwnerTag::Gateway(self.id()),
@ -230,7 +243,7 @@ impl NetworkState {
};
// Get the external network state
let external_network_state = machine_registry_inner
let mut external_network_state = machine_registry_inner
.network_states()
.get_state(gateway_params.external_network)
.expect("must succeed");
@ -255,6 +268,11 @@ impl NetworkState {
)?
};
// Update external network
machine_registry_inner
.network_states_mut()
.set_state(external_network_state);
// Return the gateway state
Some(NetworkStateIpv4Gateway {
params: gateway_params,
@ -267,38 +285,85 @@ impl NetworkState {
let ipv4 = NetworkStateIpv4 { params, gateway };
inner.ipv4 = Some(ipv4);
// Update fields
self.fields = Arc::new(NetworkStateFields {
ipv4: Some(ipv4),
address_pool,
..(*self.fields).clone()
});
Ok(())
}
pub fn clear_ipv6(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
) -> MachineRegistryResult<()> {
Self::clear_ipv6_inner(self.id(), &mut *inner, machine_registry_inner)
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(),
})?;
// 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
.network_states()
.get_state(gateway.params.external_network)
.expect("must succeed");
// Release external address
external_network_state
.release_address_v6(gateway.external_interface_address.ip)
.expect("must succeed");
// Update external network
machine_registry_inner
.network_states_mut()
.set_state(external_network_state);
}
}
// Update fields
self.fields = Arc::new(NetworkStateFields {
ipv6: None,
address_pool,
..(*self.fields).clone()
});
Ok(())
}
pub fn set_ipv6(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
params: NetworkStateIpv6Params,
gateway_params: Option<NetworkStateIpv6GatewayParams>,
) -> MachineRegistryResult<()> {
Self::clear_ipv6_inner(self.id(), &mut *inner, machine_registry_inner)?;
self.clear_ipv6(machine_registry_inner)?;
inner.address_pool.add_scope_v6(params.allocation);
let mut address_pool = self.fields.address_pool.clone();
address_pool.add_scope_v6(params.allocation);
let gateway = match gateway_params {
Some(gateway_params) => {
// Allocate or reserve an internal network address for the gateway
let internal_address =
if let Some(internal_address) = gateway_params.internal_address {
inner.address_pool.reserve_allocation_v6(
address_pool.reserve_allocation_v6(
Ipv6Net::new(internal_address, 128).expect("must succeed"),
Some(OwnerTag::Gateway(self.id())),
)?;
internal_address
} else {
let Some(internal_address) = inner.address_pool.allocate_random_v6(
let Some(internal_address) = address_pool.allocate_random_v6(
machine_registry_inner.srng(),
128,
OwnerTag::Gateway(self.id()),
@ -317,7 +382,7 @@ impl NetworkState {
};
// Get the external network state
let external_network_state = machine_registry_inner
let mut external_network_state = machine_registry_inner
.network_states()
.get_state(gateway_params.external_network)
.expect("must succeed");
@ -342,6 +407,11 @@ impl NetworkState {
)?
};
// Update external network
machine_registry_inner
.network_states_mut()
.set_state(external_network_state);
// Return the gateway state
Some(NetworkStateIpv6Gateway {
params: gateway_params,
@ -354,30 +424,36 @@ impl NetworkState {
let ipv6 = NetworkStateIpv6 { params, gateway };
inner.ipv6 = Some(ipv6);
// Update fields
self.fields = Arc::new(NetworkStateFields {
ipv6: Some(ipv6),
address_pool,
..(*self.fields).clone()
});
Ok(())
}
pub fn is_ipv4(&self) -> bool {
self.fields.lock().ipv4.is_some()
self.fields.ipv4.is_some()
}
pub fn is_ipv6(&self) -> bool {
self.fields.lock().ipv6.is_some()
self.fields.ipv6.is_some()
}
pub fn is_active(&self) -> MachineRegistryResult<bool> {
let mut can_allocate = false;
if inner.ipv4.is_some() {
if self.fields.ipv4.is_some() {
//
if !inner.address_pool.can_allocate_v4(32)? {
if !self.fields.address_pool.can_allocate_v4(32)? {
can_allocate = false;
}
}
if inner.ipv6.is_some() {
if self.fields.ipv6.is_some() {
//
if !inner.address_pool.can_allocate_v6(128)? {
if !self.fields.address_pool.can_allocate_v6(128)? {
can_allocate = false;
}
}
@ -390,61 +466,103 @@ impl NetworkState {
owner_tag: OwnerTag,
opt_address: Option<Ipv4Addr>,
) -> MachineRegistryResult<Ifv4Addr> {
let mut inner = self.fields.lock();
let net = Self::allocate_net_v4_inner(
&mut *inner,
machine_registry_inner,
owner_tag,
opt_address,
32,
)?;
let net = self.allocate_subnet_v4(machine_registry_inner, owner_tag, opt_address, 32)?;
let ip = net.addr();
let ipv4 = self.fields.ipv4.as_ref().unwrap();
let netmask = ipv4.params.allocation.netmask();
let broadcast = ipv4.params.allocation.broadcast();
let ifaddr = Ifv4Addr {
ip,
netmask: inner.ipv4.as_ref().unwrap().params.allocation.netmask(),
broadcast: Some(inner.ipv4.as_ref().unwrap().params.allocation.broadcast()),
netmask,
broadcast: Some(broadcast),
};
Ok(ifaddr)
}
pub fn can_allocate_address_v4(&self, opt_address: Option<Ipv4Addr>) -> bool {
Self::can_allocate_net_v4_inner(&*inner, opt_address, 32)
self.can_allocate_subnet_v4(opt_address, 32)
}
pub fn allocate_subnet_v4(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
owner_tag: OwnerTag,
opt_address: Option<Ipv4Addr>,
prefix: u8,
) -> MachineRegistryResult<Ipv4Net> {
let net = Self::allocate_net_v4_inner(
&mut *inner,
machine_registry_inner,
owner_tag,
opt_address,
prefix,
)?;
if self.fields.ipv4.is_none() {
return Err(MachineRegistryError::NoAllocation);
}
// See if we are requesting a specific address
let mut address_pool = self.fields.address_pool.clone();
let net = if let Some(address) = opt_address {
// Get the net form for this address
let net = Ipv4Net::new(address, prefix).expect("must succeed");
address_pool.reserve_allocation_v4(net, Some(owner_tag))?;
net
} else {
// Get a random address if available
let Some(allocation) = address_pool.allocate_random_v4(
machine_registry_inner.srng(),
prefix,
owner_tag,
)?
else {
return Err(MachineRegistryError::NoAllocation);
};
allocation
};
// Update fields
self.fields = Arc::new(NetworkStateFields {
address_pool,
..(*self.fields).clone()
});
Ok(net)
}
pub fn can_allocate_subnet_v4(&self, opt_address: Option<Ipv4Addr>, prefix: u8) -> bool {
Self::can_allocate_net_v4_inner(&*inner, opt_address, prefix)
if self.fields.ipv4.is_none() {
return false;
};
// See if we are requesting a specific address
if let Some(address) = opt_address {
// Get the net form for this address
let net = Ipv4Net::new(address, prefix).expect("must succeed");
self.fields.address_pool.get_overlaps_v4(net).is_empty()
} else {
// Get a random address if available
self.fields
.address_pool
.can_allocate_v4(prefix)
.unwrap_or(false)
}
}
pub fn release_address_v4(
&mut self,
addr: Ipv4Addr,
) -> MachineRegistryResult<Option<OwnerTag>> {
Self::release_subnet_v4_inner(&mut *inner, Ipv4Net::new(addr, 32).expect("must succeed"))
self.release_subnet_v4(Ipv4Net::new(addr, 32).expect("must succeed"))
}
pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult<Option<OwnerTag>> {
Self::release_subnet_v4_inner(&mut *inner, net)
let mut address_pool = self.fields.address_pool.clone();
let opt_tag = address_pool.release_allocation_v4(net)?;
// Update fields
self.fields = Arc::new(NetworkStateFields {
address_pool,
..(*self.fields).clone()
});
Ok(opt_tag)
}
pub fn allocate_address_v6(
@ -453,157 +571,69 @@ impl NetworkState {
owner_tag: OwnerTag,
opt_address: Option<Ipv6Addr>,
) -> MachineRegistryResult<Ifv6Addr> {
let net = Self::allocate_net_v6_inner(
&mut *inner,
machine_registry_inner,
owner_tag,
opt_address,
128,
)?;
let net = self.allocate_subnet_v6(machine_registry_inner, owner_tag, opt_address, 128)?;
let ip = net.addr();
let ipv6 = self.fields.ipv6.as_ref().unwrap();
let netmask = ipv6.params.allocation.netmask();
let broadcast = ipv6.params.allocation.broadcast();
let ifaddr = Ifv6Addr {
ip,
netmask: inner.ipv6.as_ref().unwrap().params.allocation.netmask(),
broadcast: Some(inner.ipv6.as_ref().unwrap().params.allocation.broadcast()),
netmask,
broadcast: Some(broadcast),
};
Ok(ifaddr)
}
pub fn can_allocate_address_v6(&self, opt_address: Option<Ipv6Addr>) -> bool {
Self::can_allocate_net_v6_inner(&*inner, opt_address, 128)
self.can_allocate_subnet_v6(opt_address, 128)
}
pub fn allocate_subnet_v6(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
owner_tag: OwnerTag,
opt_address: Option<Ipv6Addr>,
prefix: u8,
) -> MachineRegistryResult<Ipv6Net> {
let net = Self::allocate_net_v6_inner(
&mut *inner,
machine_registry_inner,
owner_tag,
opt_address,
prefix,
)?;
if self.fields.ipv6.is_none() {
return Err(MachineRegistryError::NoAllocation);
}
// See if we are requesting a specific address
let mut address_pool = self.fields.address_pool.clone();
let net = if let Some(address) = opt_address {
// Get the net form for this address
let net = Ipv6Net::new(address, prefix).expect("must succeed");
address_pool.reserve_allocation_v6(net, Some(owner_tag))?;
net
} else {
// Get a random address if available
let Some(allocation) = address_pool.allocate_random_v6(
machine_registry_inner.srng(),
prefix,
owner_tag,
)?
else {
return Err(MachineRegistryError::NoAllocation);
};
allocation
};
// Update fields
self.fields = Arc::new(NetworkStateFields {
address_pool,
..(*self.fields).clone()
});
Ok(net)
}
pub fn can_allocate_subnet_v6(&self, opt_address: Option<Ipv6Addr>, prefix: u8) -> bool {
Self::can_allocate_net_v6_inner(&*inner, opt_address, prefix)
}
pub fn release_address_v6(&self, addr: Ipv6Addr) -> MachineRegistryResult<Option<OwnerTag>> {
Self::release_subnet_v6_inner(&mut *inner, Ipv6Net::new(addr, 128).expect("must succeed"))
}
pub fn release_subnet_v6(&self, net: Ipv6Net) -> MachineRegistryResult<Option<OwnerTag>> {
Self::release_subnet_v6_inner(&mut *inner, net)
}
////////////////////////////////////////////////////////////////
fn clear_ipv6_inner(
self_id: NetworkStateId,
inner: &mut NetworkStateFields,
machine_registry_inner: &mut MachineRegistryInner,
) -> MachineRegistryResult<()> {
let Some(ipv6) = inner.ipv6.as_mut() else {
return Ok(());
};
inner.address_pool.clear_ipv6(|_n, t| match t {
OwnerTag::Machine(_) => true,
OwnerTag::Network(nsid) => *nsid != self_id,
OwnerTag::Gateway(nsid) => *nsid != self_id,
})?;
// 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 external_network_state = machine_registry_inner
.network_states()
.get_state(gateway.params.external_network)
.expect("must succeed");
// Release external address
external_network_state
.release_address_v6(gateway.external_interface_address.ip)
.expect("must succeed");
}
}
inner.ipv6 = None;
Ok(())
}
fn allocate_net_v4_inner(
inner: &mut NetworkStateFields,
machine_registry_inner: &mut MachineRegistryInner,
owner_tag: OwnerTag,
opt_address: Option<Ipv4Addr>,
prefix: u8,
) -> MachineRegistryResult<Ipv4Net> {
let Some(_network_state_ipv4) = &mut inner.ipv4 else {
return Err(MachineRegistryError::NoAllocation);
};
// See if we are requesting a specific address
let net = if let Some(address) = opt_address {
// Get the net form for this address
let net = Ipv4Net::new(address, prefix).expect("must succeed");
inner
.address_pool
.reserve_allocation_v4(net, Some(owner_tag))?;
net
} else {
// Get a random address if available
let Some(allocation) = inner.address_pool.allocate_random_v4(
machine_registry_inner.srng(),
prefix,
owner_tag,
)?
else {
return Err(MachineRegistryError::NoAllocation);
};
allocation
};
Ok(net)
}
fn can_allocate_net_v4_inner(
inner: &NetworkStateFields,
opt_address: Option<Ipv4Addr>,
prefix: u8,
) -> bool {
let Some(_network_state_ipv4) = &inner.ipv4 else {
return false;
};
// See if we are requesting a specific address
if let Some(address) = opt_address {
// Get the net form for this address
let net = Ipv4Net::new(address, prefix).expect("must succeed");
inner.address_pool.get_overlaps_v4(net).is_empty()
} else {
// Get a random address if available
inner.address_pool.can_allocate_v4(prefix).unwrap_or(false)
}
}
fn can_allocate_net_v6_inner(
inner: &NetworkStateFields,
opt_address: Option<Ipv6Addr>,
prefix: u8,
) -> bool {
let Some(_network_state_ipv6) = &inner.ipv6 else {
if self.fields.ipv6.is_none() {
return false;
};
@ -611,97 +641,34 @@ impl NetworkState {
if let Some(address) = opt_address {
// Get the net form for this address
let net = Ipv6Net::new(address, prefix).expect("must succeed");
inner.address_pool.get_overlaps_v6(net).is_empty()
self.fields.address_pool.get_overlaps_v6(net).is_empty()
} else {
// Get a random address if available
inner.address_pool.can_allocate_v6(prefix).unwrap_or(false)
}
}
fn allocate_net_v6_inner(
inner: &mut NetworkStateFields,
machine_registry_inner: &mut MachineRegistryInner,
owner_tag: OwnerTag,
opt_address: Option<Ipv6Addr>,
prefix: u8,
) -> MachineRegistryResult<Ipv6Net> {
let Some(_network_state_ipv6) = &mut inner.ipv6 else {
return Err(MachineRegistryError::NoAllocation);
};
// See if we are requesting a specific address
let net = if let Some(address) = opt_address {
// Get the net form for this address
let net = Ipv6Net::new(address, prefix).expect("must succeed");
inner
self.fields
.address_pool
.reserve_allocation_v6(net, Some(owner_tag))?;
net
} else {
// Get a random address if available
let Some(allocation) = inner.address_pool.allocate_random_v6(
machine_registry_inner.srng(),
prefix,
owner_tag,
)?
else {
return Err(MachineRegistryError::NoAllocation);
};
allocation
};
Ok(net)
}
fn release_subnet_v4_inner(
inner: &mut NetworkStateFields,
net: Ipv4Net,
) -> MachineRegistryResult<Option<OwnerTag>> {
inner.address_pool.release_allocation_v4(net)
}
fn release_subnet_v6_inner(
inner: &mut NetworkStateFields,
net: Ipv6Net,
) -> MachineRegistryResult<Option<OwnerTag>> {
inner.address_pool.release_allocation_v6(net)
}
pub fn release_all_addresses<I: Iterator<Item = IpAddr>>(
&self,
addrs: I,
) -> MachineRegistryResult<()> {
let mut ok = true;
for addr in addrs {
match addr {
IpAddr::V4(ipv4_addr) => {
if Self::release_subnet_v4_inner(
&mut *inner,
Ipv4Net::new(ipv4_addr, 32).expect("must succeed"),
)
.is_err()
{
ok = false;
}
}
IpAddr::V6(ipv6_addr) => {
if Self::release_subnet_v6_inner(
&mut *inner,
Ipv6Net::new(ipv6_addr, 128).expect("must succeed"),
)
.is_err()
{
ok = false;
}
}
}
}
if ok {
Ok(())
} else {
Err(MachineRegistryError::NoAllocation)
.can_allocate_v6(prefix)
.unwrap_or(false)
}
}
pub fn release_address_v6(
&mut self,
addr: Ipv6Addr,
) -> MachineRegistryResult<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>> {
let mut address_pool = self.fields.address_pool.clone();
let opt_tag = address_pool.release_allocation_v6(net)?;
// Update fields
self.fields = Arc::new(NetworkStateFields {
address_pool,
..(*self.fields).clone()
});
Ok(opt_tag)
}
}
impl State for NetworkState {

View File

@ -1,15 +1,15 @@
use super::*;
#[derive(Debug)]
struct TemplateStateUnlockedInner {
struct TemplateStateImmutable {
id: TemplateStateId,
name: String,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
struct PerNetworkInfo {
limit_machine_count: Option<usize>,
machines: HashSet<MachineStateId>,
machines: imbl::HashSet<MachineStateId>,
}
#[derive(Debug, Clone)]
@ -18,20 +18,20 @@ enum BlueprintAvailability {
Generate(BlueprintState),
}
#[derive(Debug)]
struct TemplateStateInner {
#[derive(Debug, Clone)]
struct TemplateStateFields {
limit_machine_count: Option<usize>,
limit_machines_per_network: Option<WeightedList<usize>>,
locations_list: Option<MachineLocationsList>,
machines: HashSet<MachineStateId>,
machines_per_network: HashMap<NetworkStateId, PerNetworkInfo>,
disable_capabilities: Vec<String>,
machines: imbl::HashSet<MachineStateId>,
machines_per_network: imbl::HashMap<NetworkStateId, PerNetworkInfo>,
disable_capabilities: imbl::Vector<Arc<String>>,
}
#[derive(Debug, Clone)]
pub struct TemplateState {
unlocked_inner: Arc<TemplateStateUnlockedInner>,
inner: Arc<Mutex<TemplateStateInner>>,
immutable: Arc<TemplateStateImmutable>,
fields: Arc<TemplateStateFields>,
}
pub type TemplateStateId = StateId<TemplateState>;
@ -39,61 +39,85 @@ pub type TemplateStateId = StateId<TemplateState>;
impl TemplateState {
pub fn new(id: TemplateStateId, name: String) -> Self {
Self {
unlocked_inner: Arc::new(TemplateStateUnlockedInner { id, name }),
inner: Arc::new(Mutex::new(TemplateStateInner {
immutable: Arc::new(TemplateStateImmutable { id, name }),
fields: Arc::new(TemplateStateFields {
limit_machine_count: None,
limit_machines_per_network: None,
locations_list: None,
machines: HashSet::new(),
machines_per_network: HashMap::new(),
disable_capabilities: Vec::new(),
})),
machines: imbl::HashSet::new(),
machines_per_network: imbl::HashMap::new(),
disable_capabilities: imbl::Vector::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_disable_capabilities(&mut self, disable_capabilities: Vec<String>) {
let disable_capabilities =
imbl::Vector::from_iter(disable_capabilities.into_iter().map(Arc::new));
// Update fields
self.fields = Arc::new(TemplateStateFields {
disable_capabilities,
..(*self.fields).clone()
});
}
pub fn set_networks_list(&self, networks: WeightedList<NetworkStateId>) {
let mut inner = self.inner.lock();
inner.locations_list = Some(MachineLocationsList::Networks { networks })
pub fn set_networks_list(&mut self, networks: WeightedList<NetworkStateId>) {
let locations_list = Some(MachineLocationsList::Networks { networks });
// Update fields
self.fields = Arc::new(TemplateStateFields {
locations_list,
..(*self.fields).clone()
});
}
pub fn set_blueprints_list(&self, blueprints: WeightedList<BlueprintStateId>) {
let mut inner = self.inner.lock();
inner.locations_list = Some(MachineLocationsList::Blueprints { blueprints })
pub fn set_blueprints_list(mut self, blueprints: WeightedList<BlueprintStateId>) {
let locations_list = Some(MachineLocationsList::Blueprints { blueprints });
// Update fields
self.fields = Arc::new(TemplateStateFields {
locations_list,
..(*self.fields).clone()
});
}
pub fn clear_locations_list(&self) {
let mut inner = self.inner.lock();
inner.locations_list = None;
pub fn clear_locations_list(&mut self) {
let locations_list = None;
// Update fields
self.fields = Arc::new(TemplateStateFields {
locations_list,
..(*self.fields).clone()
});
}
pub fn set_limit_machine_count(&self, limit_machine_count: Option<usize>) {
let mut inner = self.inner.lock();
inner.limit_machine_count = limit_machine_count;
pub fn set_limit_machine_count(&mut self, limit_machine_count: Option<usize>) {
// Update fields
self.fields = Arc::new(TemplateStateFields {
limit_machine_count,
..(*self.fields).clone()
});
}
pub fn set_limit_machines_per_network(
&self,
&mut self,
limit_machines_per_network: Option<WeightedList<usize>>,
) {
let mut inner = self.inner.lock();
inner.limit_machines_per_network = limit_machines_per_network;
// Update fields
self.fields = Arc::new(TemplateStateFields {
limit_machines_per_network,
..(*self.fields).clone()
});
}
fn is_network_available_inner(
inner: &TemplateStateInner,
network_state: NetworkState,
) -> MachineRegistryResult<bool> {
fn is_network_available(&self, network_state: NetworkState) -> MachineRegistryResult<bool> {
// If the network is not active, it is not available
if !network_state.is_active()? {
return Ok(false);
}
// Get the per network info
let Some(pni) = inner.machines_per_network.get(&network_state.id()) else {
let Some(pni) = self.fields.machines_per_network.get(&network_state.id()) else {
// If we haven't allocated anything in the network yet it is
// by definition available
return Ok(true);
@ -110,8 +134,8 @@ impl TemplateState {
Ok(true)
}
fn is_blueprint_available_inner(
inner: &TemplateStateInner,
fn is_blueprint_available(
&self,
machine_registry_inner: &MachineRegistryInner,
blueprint_state: BlueprintState,
) -> MachineRegistryResult<Option<BlueprintAvailability>> {
@ -120,7 +144,7 @@ impl TemplateState {
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_inner(inner, network_state.clone())? {
if self.is_network_available(network_state.clone())? {
// We found one
return Ok(Some(network_state));
}
@ -145,16 +169,14 @@ impl TemplateState {
&self,
machine_registry_inner: &MachineRegistryInner,
) -> MachineRegistryResult<bool> {
let inner = self.inner.lock();
// See if we have reached our machine limit
if let Some(limit_machine_count) = inner.limit_machine_count {
if inner.machines.len() >= limit_machine_count {
if let Some(limit_machine_count) = self.fields.limit_machine_count {
if self.fields.machines.len() >= limit_machine_count {
return Ok(false);
}
}
let Some(locations_list) = inner.locations_list.as_ref() else {
let Some(locations_list) = self.fields.locations_list.as_ref() else {
return Ok(false);
};
@ -165,7 +187,7 @@ impl TemplateState {
.try_filter(|id| {
let network_state =
machine_registry_inner.network_states().get_state(*id)?;
Self::is_network_available_inner(&*inner, network_state)
self.is_network_available(network_state)
})?
.is_none()
{
@ -179,12 +201,8 @@ impl TemplateState {
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())
self.is_blueprint_available(machine_registry_inner, blueprint_state)
.map(|x| x.is_some())
})?
.is_none()
{
@ -200,17 +218,15 @@ impl TemplateState {
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
) -> MachineRegistryResult<MachineStateId> {
let mut inner = self.inner.lock();
// See if we have reached our machine limit
if let Some(limit_machine_count) = inner.limit_machine_count {
if inner.machines.len() < limit_machine_count.try_into().unwrap_or(usize::MAX) {
if let Some(limit_machine_count) = self.fields.limit_machine_count {
if self.fields.machines.len() < limit_machine_count.try_into().unwrap_or(usize::MAX) {
return Err(MachineRegistryError::TemplateComplete);
}
}
// 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) = inner.locations_list.as_ref() else {
let Some(locations_list) = self.fields.locations_list.as_ref() else {
return Err(MachineRegistryError::TemplateComplete);
};
@ -220,7 +236,7 @@ impl TemplateState {
// 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)?;
if Self::is_network_available_inner(&*inner, network_state.clone())? {
if self.is_network_available(network_state.clone())? {
Ok(Some(network_state))
} else {
Ok(None)
@ -244,11 +260,7 @@ impl TemplateState {
let blueprint_state =
machine_registry_inner.blueprint_states().get_state(*id)?;
Self::is_blueprint_available_inner(
&*inner,
machine_registry_inner,
blueprint_state,
)
self.is_blueprint_available(machine_registry_inner, blueprint_state)
})?
else {
return Err(MachineRegistryError::BlueprintComplete);
@ -270,6 +282,8 @@ impl TemplateState {
// Allocate a machine id
let machine_state_id = machine_registry_inner.machine_states_mut().allocate_id();
xxx continue here
// Create an anonymous machine state
let machine_state = MachineState::new(machine_state_id, None);
@ -309,8 +323,12 @@ impl TemplateState {
.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_ref(&wl).clone());
let limit_machine_count = limit_machines_per_network.map(|wl| {
machine_registry_inner
.srng()
.weighted_choice_ref(&wl)
.clone()
});
PerNetworkInfo {
limit_machine_count,
machines: HashSet::new(),