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

View File

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

View File

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