mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-02-10 03:38:36 -05:00
[skip ci] tracing options
This commit is contained in:
parent
a7eee5574b
commit
a16a54de0c
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6660,6 +6660,7 @@ dependencies = [
|
|||||||
"static_assertions",
|
"static_assertions",
|
||||||
"stop-token",
|
"stop-token",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
@ -16,6 +16,11 @@ resolver = "2"
|
|||||||
crate-type = ["cdylib", "staticlib", "rlib"]
|
crate-type = ["cdylib", "staticlib", "rlib"]
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "virtual_router"
|
||||||
|
path = "src/bin/virtual_router/main.rs"
|
||||||
|
required-features = ["virtual-router"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt-tokio", "virtual-network", "virtual-network-server"]
|
default = ["rt-tokio", "virtual-network", "virtual-network-server"]
|
||||||
rt-async-std = [
|
rt-async-std = [
|
||||||
@ -54,6 +59,7 @@ virtual-network-server = [
|
|||||||
"dep:ws_stream_tungstenite",
|
"dep:ws_stream_tungstenite",
|
||||||
"dep:rand_chacha",
|
"dep:rand_chacha",
|
||||||
]
|
]
|
||||||
|
virtual-router = ["tracing", "virtual-network-server", "dep:time"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tracing = { version = "0.1.40", features = [
|
tracing = { version = "0.1.40", features = [
|
||||||
@ -62,6 +68,7 @@ tracing = { version = "0.1.40", features = [
|
|||||||
], optional = true }
|
], optional = true }
|
||||||
tracing-subscriber = { version = "0.3.18", features = [
|
tracing-subscriber = { version = "0.3.18", features = [
|
||||||
"env-filter",
|
"env-filter",
|
||||||
|
"time",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
log = { version = "0.4.22" }
|
log = { version = "0.4.22" }
|
||||||
eyre = "0.6.12"
|
eyre = "0.6.12"
|
||||||
@ -86,11 +93,16 @@ range-set-blaze = "0.1.16"
|
|||||||
flume = { version = "0.11.0", features = ["async"] }
|
flume = { version = "0.11.0", features = ["async"] }
|
||||||
imbl = { version = "3.0.0", features = ["serde"] }
|
imbl = { version = "3.0.0", features = ["serde"] }
|
||||||
|
|
||||||
|
|
||||||
# Dependencies for native builds only
|
# Dependencies for native builds only
|
||||||
# Linux, Windows, Mac, iOS, Android
|
# Linux, Windows, Mac, iOS, Android
|
||||||
[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies]
|
[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies]
|
||||||
async-io = { version = "1.13.0" }
|
async-io = { version = "1.13.0" }
|
||||||
async-std = { version = "1.12.0", features = ["unstable"], optional = true }
|
async-std = { version = "1.12.0", features = ["unstable"], optional = true }
|
||||||
|
time = { version = "0.3.36", features = [
|
||||||
|
"local-offset",
|
||||||
|
"formatting",
|
||||||
|
], optional = true }
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
ctrlc = "^3"
|
ctrlc = "^3"
|
||||||
futures-util = { version = "0.3.30", default-features = false, features = [
|
futures-util = { version = "0.3.30", default-features = false, features = [
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#![cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
#![cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
|
||||||
use cfg_if::*;
|
use cfg_if::*;
|
||||||
use clap::Parser;
|
use clap::{Args, Parser};
|
||||||
use parking_lot::*;
|
use parking_lot::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use stop_token::StopSource;
|
use stop_token::StopSource;
|
||||||
|
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, Layer, Registry};
|
||||||
use veilid_tools::*;
|
use veilid_tools::*;
|
||||||
use virtual_network::*;
|
use virtual_network::*;
|
||||||
|
|
||||||
@ -26,6 +27,25 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_IGNORE_LOG_TARGETS: &[&str] = &["tokio"];
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
#[group(multiple = false)]
|
||||||
|
pub struct Logging {
|
||||||
|
/// Turn on debug logging on the terminal
|
||||||
|
#[arg(long, group = "logging")]
|
||||||
|
debug: bool,
|
||||||
|
/// Turn on trace logging on the terminal
|
||||||
|
#[arg(long, group = "logging")]
|
||||||
|
trace: bool,
|
||||||
|
/// Ignore log targets
|
||||||
|
#[arg(long)]
|
||||||
|
ignore_log_targets: Vec<String>,
|
||||||
|
/// Enable log targets
|
||||||
|
#[arg(long)]
|
||||||
|
enable_log_targets: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about = "Veilid VirtualRouter")]
|
#[command(author, version, about = "Veilid VirtualRouter")]
|
||||||
struct CmdlineArgs {
|
struct CmdlineArgs {
|
||||||
@ -50,6 +70,66 @@ struct CmdlineArgs {
|
|||||||
/// Instead of running the virtual router, print the configuration it would use to the console
|
/// Instead of running the virtual router, print the configuration it would use to the console
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
dump_config: bool,
|
dump_config: bool,
|
||||||
|
|
||||||
|
#[command(flatten)]
|
||||||
|
logging: Logging,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_tracing(logging: &Logging) -> Result<(), String> {
|
||||||
|
// Set up subscriber and layers
|
||||||
|
let subscriber = Registry::default();
|
||||||
|
let mut layers = Vec::new();
|
||||||
|
|
||||||
|
// Get log level
|
||||||
|
let level = if logging.trace {
|
||||||
|
tracing::Level::TRACE
|
||||||
|
} else if logging.debug {
|
||||||
|
tracing::Level::DEBUG
|
||||||
|
} else {
|
||||||
|
tracing::Level::INFO
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get ignore log targets
|
||||||
|
let mut ignore_log_targets: Vec<String> = DEFAULT_IGNORE_LOG_TARGETS
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.collect();
|
||||||
|
for x in &logging.ignore_log_targets {
|
||||||
|
if !ignore_log_targets.contains(x) {
|
||||||
|
ignore_log_targets.push(x.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ignore_log_targets.retain(|x| !logging.enable_log_targets.contains(x));
|
||||||
|
|
||||||
|
let timer =
|
||||||
|
time::format_description::parse("[hour]:[minute]:[second]").expect("invalid time format");
|
||||||
|
|
||||||
|
// Use chrono instead of time crate to get local offset
|
||||||
|
let offset_in_sec = chrono::Local::now().offset().local_minus_utc();
|
||||||
|
let time_offset =
|
||||||
|
time::UtcOffset::from_whole_seconds(offset_in_sec).expect("invalid utc offset");
|
||||||
|
let timer = fmt::time::OffsetTime::new(time_offset, timer);
|
||||||
|
|
||||||
|
let mut filter = tracing_subscriber::EnvFilter::from_default_env().add_directive(level.into());
|
||||||
|
for x in ignore_log_targets {
|
||||||
|
filter = filter.add_directive(format!("{x}=off").parse().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let layer = fmt::Layer::new()
|
||||||
|
.compact()
|
||||||
|
.with_timer(timer)
|
||||||
|
.with_ansi(true)
|
||||||
|
.with_writer(std::io::stdout)
|
||||||
|
.with_filter(filter);
|
||||||
|
|
||||||
|
layers.push(layer.boxed());
|
||||||
|
|
||||||
|
let subscriber = subscriber.with(layers);
|
||||||
|
subscriber
|
||||||
|
.try_init()
|
||||||
|
.map_err(|e| format!("failed to initialize tracing: {e}"))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn main() -> Result<(), String> {
|
||||||
@ -68,6 +148,8 @@ fn main() -> Result<(), String> {
|
|||||||
|
|
||||||
let args = CmdlineArgs::parse();
|
let args = CmdlineArgs::parse();
|
||||||
|
|
||||||
|
setup_tracing(&args.logging)?;
|
||||||
|
|
||||||
let initial_config = config::Config::new(&args.config_file, args.no_predefined_config)
|
let initial_config = config::Config::new(&args.config_file, args.no_predefined_config)
|
||||||
.map_err(|e| format!("Error loading config: {}", e))?;
|
.map_err(|e| format!("Error loading config: {}", e))?;
|
||||||
|
|
||||||
|
@ -61,9 +61,6 @@ pub enum MachineLocation {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
address6: Option<Ipv6Addr>,
|
address6: Option<Ipv6Addr>,
|
||||||
},
|
},
|
||||||
Blueprint {
|
|
||||||
blueprint: String,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Validate for MachineLocation {
|
impl Validate for MachineLocation {
|
||||||
@ -83,7 +80,6 @@ impl Validate for MachineLocation {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MachineLocation::Blueprint { blueprint: _ } => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
|
@ -136,8 +136,14 @@ impl GlobalStateManagerInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create all template states
|
// Create all template states
|
||||||
|
for (name, template) in cfg.templates {
|
||||||
|
self.execute_config_template(name, template)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Create all machine states
|
// Create all machine states
|
||||||
|
for (name, machine) in cfg.machines {
|
||||||
|
self.execute_config_machine(name, machine)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -647,7 +653,7 @@ impl GlobalStateManagerInner {
|
|||||||
|
|
||||||
let locations = match ipv4.location.clone() {
|
let locations = match ipv4.location.clone() {
|
||||||
config::BlueprintLocation::Allocation { allocation } => {
|
config::BlueprintLocation::Allocation { allocation } => {
|
||||||
NetworkLocationsList::Allocations {
|
BlueprintLocationsList::Allocations {
|
||||||
allocations: allocation,
|
allocations: allocation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -658,7 +664,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(n)
|
.get_state_id_by_name(n)
|
||||||
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
||||||
})?;
|
})?;
|
||||||
NetworkLocationsList::Networks { networks }
|
BlueprintLocationsList::Networks { networks }
|
||||||
} else {
|
} else {
|
||||||
let default_network = self.or_default_network(None)?;
|
let default_network = self.or_default_network(None)?;
|
||||||
let default_network_state_id = self
|
let default_network_state_id = self
|
||||||
@ -666,7 +672,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(&default_network)
|
.get_state_id_by_name(&default_network)
|
||||||
.ok_or(GlobalStateManagerError::NetworkNotFound(default_network))?;
|
.ok_or(GlobalStateManagerError::NetworkNotFound(default_network))?;
|
||||||
|
|
||||||
NetworkLocationsList::Networks {
|
BlueprintLocationsList::Networks {
|
||||||
networks: WeightedList::Single(default_network_state_id),
|
networks: WeightedList::Single(default_network_state_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +720,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(n)
|
.get_state_id_by_name(n)
|
||||||
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
||||||
})?;
|
})?;
|
||||||
Some(MachineLocationsList::Networks { networks })
|
Some(TemplateLocationsList::Networks { networks })
|
||||||
}
|
}
|
||||||
Some(config::TemplateLocation::Blueprint { blueprint }) => {
|
Some(config::TemplateLocation::Blueprint { blueprint }) => {
|
||||||
let blueprints = blueprint.try_map(|n| {
|
let blueprints = blueprint.try_map(|n| {
|
||||||
@ -722,7 +728,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(n)
|
.get_state_id_by_name(n)
|
||||||
.ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(n.clone()))
|
.ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(n.clone()))
|
||||||
})?;
|
})?;
|
||||||
Some(MachineLocationsList::Blueprints { blueprints })
|
Some(TemplateLocationsList::Blueprints { blueprints })
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
@ -757,7 +763,7 @@ impl GlobalStateManagerInner {
|
|||||||
|
|
||||||
let locations = match ipv6.location.clone() {
|
let locations = match ipv6.location.clone() {
|
||||||
config::BlueprintLocation::Allocation { allocation } => {
|
config::BlueprintLocation::Allocation { allocation } => {
|
||||||
NetworkLocationsList::Allocations {
|
BlueprintLocationsList::Allocations {
|
||||||
allocations: allocation,
|
allocations: allocation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -768,7 +774,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(n)
|
.get_state_id_by_name(n)
|
||||||
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
||||||
})?;
|
})?;
|
||||||
NetworkLocationsList::Networks { networks }
|
BlueprintLocationsList::Networks { networks }
|
||||||
} else {
|
} else {
|
||||||
let default_network = self.or_default_network(None)?;
|
let default_network = self.or_default_network(None)?;
|
||||||
let default_network_state_id = self
|
let default_network_state_id = self
|
||||||
@ -776,7 +782,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(&default_network)
|
.get_state_id_by_name(&default_network)
|
||||||
.ok_or(GlobalStateManagerError::NetworkNotFound(default_network))?;
|
.ok_or(GlobalStateManagerError::NetworkNotFound(default_network))?;
|
||||||
|
|
||||||
NetworkLocationsList::Networks {
|
BlueprintLocationsList::Networks {
|
||||||
networks: WeightedList::Single(default_network_state_id),
|
networks: WeightedList::Single(default_network_state_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -824,7 +830,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(n)
|
.get_state_id_by_name(n)
|
||||||
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone()))
|
||||||
})?;
|
})?;
|
||||||
Some(MachineLocationsList::Networks { networks })
|
Some(TemplateLocationsList::Networks { networks })
|
||||||
}
|
}
|
||||||
Some(config::TemplateLocation::Blueprint { blueprint }) => {
|
Some(config::TemplateLocation::Blueprint { blueprint }) => {
|
||||||
let blueprints = blueprint.try_map(|n| {
|
let blueprints = blueprint.try_map(|n| {
|
||||||
@ -832,7 +838,7 @@ impl GlobalStateManagerInner {
|
|||||||
.get_state_id_by_name(n)
|
.get_state_id_by_name(n)
|
||||||
.ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(n.clone()))
|
.ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(n.clone()))
|
||||||
})?;
|
})?;
|
||||||
Some(MachineLocationsList::Blueprints { blueprints })
|
Some(TemplateLocationsList::Blueprints { blueprints })
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
@ -851,6 +857,132 @@ impl GlobalStateManagerInner {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execute_config_template(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
template: config::Template,
|
||||||
|
) -> GlobalStateManagerResult<()> {
|
||||||
|
if self
|
||||||
|
.template_state_registry
|
||||||
|
.get_state_id_by_name(&name)
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
return Err(GlobalStateManagerError::DuplicateName(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = self.template_state_registry.allocate_id();
|
||||||
|
let state = {
|
||||||
|
let mut template_state = TemplateState::new(id, name);
|
||||||
|
|
||||||
|
template_state.set_disable_capabilities(template.disable_capabilities);
|
||||||
|
if let Some(wl) = template.limits.machine_count {
|
||||||
|
template_state.set_limit_machine_count(Some(self.srng().weighted_choice(wl)));
|
||||||
|
}
|
||||||
|
template_state
|
||||||
|
.set_limit_machines_per_network(template.limits.machines_per_network.clone());
|
||||||
|
|
||||||
|
match template.location.clone() {
|
||||||
|
config::TemplateLocation::Network { network } => {
|
||||||
|
let networks = network.try_map(|x| {
|
||||||
|
self.network_state_registry
|
||||||
|
.get_state_id_by_name(x)
|
||||||
|
.ok_or_else(|| GlobalStateManagerError::NetworkNotFound(x.clone()))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
template_state.set_networks_list(networks);
|
||||||
|
}
|
||||||
|
config::TemplateLocation::Blueprint { blueprint } => {
|
||||||
|
let blueprints = blueprint.try_map(|x| {
|
||||||
|
self.blueprint_state_registry
|
||||||
|
.get_state_id_by_name(x)
|
||||||
|
.ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(x.clone()))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
template_state.set_blueprints_list(blueprints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(template_state)
|
||||||
|
}
|
||||||
|
.inspect_err(|_| {
|
||||||
|
self.template_state_registry
|
||||||
|
.release_id(id)
|
||||||
|
.expect("must release");
|
||||||
|
})?;
|
||||||
|
self.template_state_registry
|
||||||
|
.attach_state(state)
|
||||||
|
.expect("must attach");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_config_machine(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
machine: config::Machine,
|
||||||
|
) -> GlobalStateManagerResult<()> {
|
||||||
|
if self
|
||||||
|
.machine_state_registry
|
||||||
|
.get_state_id_by_name(&name)
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
return Err(GlobalStateManagerError::DuplicateName(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = self.machine_state_registry.allocate_id();
|
||||||
|
let state = {
|
||||||
|
let mut machine_state = MachineState::new(id, Some(name), MachineOrigin::Config);
|
||||||
|
|
||||||
|
machine_state.set_disable_capabilities(machine.disable_capabilities);
|
||||||
|
machine_state.set_bootstrap(machine.bootstrap);
|
||||||
|
|
||||||
|
// Create primary interface
|
||||||
|
let interface_name = machine_state.allocate_interface(None, None)?;
|
||||||
|
|
||||||
|
match machine.location {
|
||||||
|
config::MachineLocation::Network {
|
||||||
|
network,
|
||||||
|
address4,
|
||||||
|
address6,
|
||||||
|
} => {
|
||||||
|
// Look up network
|
||||||
|
let network_state_id = self
|
||||||
|
.network_state_registry
|
||||||
|
.get_state_id_by_name(&network)
|
||||||
|
.ok_or(GlobalStateManagerError::NetworkNotFound(network))?;
|
||||||
|
|
||||||
|
machine_state.attach_network(self, &interface_name, network_state_id)?;
|
||||||
|
if let Some(address4) = address4 {
|
||||||
|
machine_state.allocate_address_ipv4(
|
||||||
|
self,
|
||||||
|
&interface_name,
|
||||||
|
Some(address4),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if let Some(address6) = address6 {
|
||||||
|
machine_state.allocate_address_ipv6(
|
||||||
|
self,
|
||||||
|
&interface_name,
|
||||||
|
Some(address6),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(machine_state)
|
||||||
|
}
|
||||||
|
.inspect_err(|_| {
|
||||||
|
self.machine_state_registry
|
||||||
|
.release_id(id)
|
||||||
|
.expect("must release");
|
||||||
|
})?;
|
||||||
|
self.machine_state_registry
|
||||||
|
.attach_state(state)
|
||||||
|
.expect("must attach");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_address_pool(
|
fn resolve_address_pool(
|
||||||
&self,
|
&self,
|
||||||
allocation_name: String,
|
allocation_name: String,
|
||||||
|
@ -10,14 +10,14 @@ struct BlueprintStateImmutable {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BlueprintStateIpv4Params {
|
pub struct BlueprintStateIpv4Params {
|
||||||
pub locations: NetworkLocationsList,
|
pub locations: BlueprintLocationsList,
|
||||||
pub prefix: WeightedList<u8>,
|
pub prefix: WeightedList<u8>,
|
||||||
pub gateway: Option<BlueprintStateGatewayParams>,
|
pub gateway: Option<BlueprintStateGatewayParams>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BlueprintStateIpv6Params {
|
pub struct BlueprintStateIpv6Params {
|
||||||
pub locations: NetworkLocationsList,
|
pub locations: BlueprintLocationsList,
|
||||||
pub prefix: WeightedList<u8>,
|
pub prefix: WeightedList<u8>,
|
||||||
pub gateway: Option<BlueprintStateGatewayParams>,
|
pub gateway: Option<BlueprintStateGatewayParams>,
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ pub struct BlueprintStateIpv6Params {
|
|||||||
pub struct BlueprintStateGatewayParams {
|
pub struct BlueprintStateGatewayParams {
|
||||||
pub translation: WeightedList<config::Translation>,
|
pub translation: WeightedList<config::Translation>,
|
||||||
pub upnp: Probability,
|
pub upnp: Probability,
|
||||||
pub locations: Option<MachineLocationsList>,
|
pub locations: Option<TemplateLocationsList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -1,181 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum BlueprintAvailability {
|
|
||||||
Existing(NetworkState),
|
|
||||||
Generate(BlueprintState),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Locations where a machine can be instantiated
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum MachineLocationsList {
|
|
||||||
Networks {
|
|
||||||
networks: WeightedList<NetworkStateId>,
|
|
||||||
},
|
|
||||||
Blueprints {
|
|
||||||
blueprints: WeightedList<BlueprintStateId>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MachineLocationsList {
|
|
||||||
pub fn can_pick<F>(
|
|
||||||
&self,
|
|
||||||
gsm_inner: &mut GlobalStateManagerInner,
|
|
||||||
mut network_filter: F,
|
|
||||||
) -> GlobalStateManagerResult<bool>
|
|
||||||
where
|
|
||||||
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
MachineLocationsList::Networks { networks } => {
|
|
||||||
// Filter the weighted list of networks to those that are still active and or not yet started
|
|
||||||
if networks
|
|
||||||
.try_filter(|id| {
|
|
||||||
let network_state = gsm_inner.network_states().get_state(*id)?;
|
|
||||||
self.is_network_available(gsm_inner, network_state, &mut network_filter)
|
|
||||||
})?
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
return Ok(false);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
MachineLocationsList::Blueprints { blueprints } => {
|
|
||||||
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
|
||||||
if blueprints
|
|
||||||
.try_filter(|id| {
|
|
||||||
let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?;
|
|
||||||
|
|
||||||
self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter)
|
|
||||||
.map(|x| x.is_some())
|
|
||||||
})?
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
return Ok(false);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pick<F>(
|
|
||||||
&self,
|
|
||||||
gsm_inner: &mut GlobalStateManagerInner,
|
|
||||||
mut network_filter: F,
|
|
||||||
) -> GlobalStateManagerResult<Option<NetworkState>>
|
|
||||||
where
|
|
||||||
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
|
|
||||||
{
|
|
||||||
// Get a network to generate the machine on
|
|
||||||
let network_state = match self {
|
|
||||||
MachineLocationsList::Networks { networks } => {
|
|
||||||
// Filter the weighted list of networks to those that are still active and or not yet started
|
|
||||||
let Some(available_networks) = networks.try_filter_map(|id| {
|
|
||||||
let network_state = gsm_inner.network_states().get_state(*id)?;
|
|
||||||
if self.is_network_available(
|
|
||||||
gsm_inner,
|
|
||||||
network_state.clone(),
|
|
||||||
&mut network_filter,
|
|
||||||
)? {
|
|
||||||
Ok(Some(network_state))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Weighted choice of network now that we have a candidate list
|
|
||||||
let network_state = gsm_inner.srng().weighted_choice(available_networks);
|
|
||||||
|
|
||||||
// Return network state to use
|
|
||||||
network_state
|
|
||||||
}
|
|
||||||
MachineLocationsList::Blueprints { blueprints } => {
|
|
||||||
// Filter the weighted list of blueprints to those that are still active or not yet started and can allocate
|
|
||||||
let Some(available_blueprints) = blueprints.try_filter_map(|id| {
|
|
||||||
let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?;
|
|
||||||
|
|
||||||
self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter)
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Weighted choice of blueprint now that we have a candidate list
|
|
||||||
match gsm_inner.srng().weighted_choice(available_blueprints) {
|
|
||||||
BlueprintAvailability::Existing(network_state) => network_state,
|
|
||||||
BlueprintAvailability::Generate(mut blueprint_state) => {
|
|
||||||
// Generate network state from blueprint state
|
|
||||||
let network_state_id = blueprint_state.generate(gsm_inner)?;
|
|
||||||
|
|
||||||
// Update blueprint state
|
|
||||||
gsm_inner.blueprint_states_mut().set_state(blueprint_state);
|
|
||||||
|
|
||||||
// Return network state
|
|
||||||
gsm_inner.network_states().get_state(network_state_id)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Some(network_state))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_network_available<F>(
|
|
||||||
&self,
|
|
||||||
gsm_inner: &GlobalStateManagerInner,
|
|
||||||
network_state: NetworkState,
|
|
||||||
mut network_filter: F,
|
|
||||||
) -> GlobalStateManagerResult<bool>
|
|
||||||
where
|
|
||||||
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
|
|
||||||
{
|
|
||||||
// If the network is not active, it is not available
|
|
||||||
if !network_state.is_active()? {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the network filter
|
|
||||||
if !network_filter(gsm_inner, network_state.id())? {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_blueprint_available<F>(
|
|
||||||
&self,
|
|
||||||
gsm_inner: &mut GlobalStateManagerInner,
|
|
||||||
blueprint_state: BlueprintState,
|
|
||||||
mut network_filter: F,
|
|
||||||
) -> GlobalStateManagerResult<Option<BlueprintAvailability>>
|
|
||||||
where
|
|
||||||
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
|
|
||||||
{
|
|
||||||
// See if the networks generated from this blueprint so far have availability
|
|
||||||
// in this template
|
|
||||||
if let Some(available_network_state) = blueprint_state.for_each_network_id(|id| {
|
|
||||||
// Check the network's availability
|
|
||||||
let network_state = gsm_inner.network_states().get_state(id)?;
|
|
||||||
if self.is_network_available(gsm_inner, network_state.clone(), &mut network_filter)? {
|
|
||||||
// We found one
|
|
||||||
return Ok(Some(network_state));
|
|
||||||
}
|
|
||||||
// Try next network
|
|
||||||
Ok(None)
|
|
||||||
})? {
|
|
||||||
// We found a usable network
|
|
||||||
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(gsm_inner) {
|
|
||||||
return Ok(Some(BlueprintAvailability::Generate(blueprint_state)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ use super::*;
|
|||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum MachineOrigin {
|
pub enum MachineOrigin {
|
||||||
InitialConfig,
|
Config,
|
||||||
Direct,
|
Direct,
|
||||||
Template(TemplateStateId),
|
Template(TemplateStateId),
|
||||||
}
|
}
|
||||||
@ -70,9 +70,7 @@ impl MachineState {
|
|||||||
.get_state(generating_template)
|
.get_state(generating_template)
|
||||||
.expect("must exist");
|
.expect("must exist");
|
||||||
template_state.on_machine_released(self.id());
|
template_state.on_machine_released(self.id());
|
||||||
gsm_inner
|
gsm_inner.template_states_mut().set_state(template_state);
|
||||||
.template_states_mut()
|
|
||||||
.set_state(template_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,9 +165,7 @@ impl MachineState {
|
|||||||
(*interface_key).clone(),
|
(*interface_key).clone(),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let mut network_state = gsm_inner
|
let mut network_state = gsm_inner.network_states().get_state(network_id)?;
|
||||||
.network_states()
|
|
||||||
.get_state(network_id)?;
|
|
||||||
|
|
||||||
// Allocate interface address
|
// Allocate interface address
|
||||||
let is_dynamic = opt_address.is_none();
|
let is_dynamic = opt_address.is_none();
|
||||||
@ -180,9 +176,7 @@ impl MachineState {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Update the network state
|
// Update the network state
|
||||||
gsm_inner
|
gsm_inner.network_states_mut().set_state(network_state);
|
||||||
.network_states_mut()
|
|
||||||
.set_state(network_state);
|
|
||||||
|
|
||||||
// Get address flags
|
// Get address flags
|
||||||
let flags = opt_address_flags.unwrap_or(AddressFlags {
|
let flags = opt_address_flags.unwrap_or(AddressFlags {
|
||||||
@ -237,9 +231,7 @@ impl MachineState {
|
|||||||
(*interface_key).clone(),
|
(*interface_key).clone(),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let mut network_state = gsm_inner
|
let mut network_state = gsm_inner.network_states().get_state(network_id)?;
|
||||||
.network_states()
|
|
||||||
.get_state(network_id)?;
|
|
||||||
|
|
||||||
// Allocate interface address
|
// Allocate interface address
|
||||||
let is_dynamic = opt_address.is_none();
|
let is_dynamic = opt_address.is_none();
|
||||||
@ -249,9 +241,7 @@ impl MachineState {
|
|||||||
opt_address,
|
opt_address,
|
||||||
)?;
|
)?;
|
||||||
// Update the network state
|
// Update the network state
|
||||||
gsm_inner
|
gsm_inner.network_states_mut().set_state(network_state);
|
||||||
.network_states_mut()
|
|
||||||
.set_state(network_state);
|
|
||||||
|
|
||||||
// Get address flags
|
// Get address flags
|
||||||
let flags = opt_address_flags.unwrap_or(AddressFlags {
|
let flags = opt_address_flags.unwrap_or(AddressFlags {
|
||||||
@ -384,9 +374,7 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the network state
|
// Get the network state
|
||||||
let mut network_state = gsm_inner
|
let mut network_state = gsm_inner.network_states().get_state(network_id)?;
|
||||||
.network_states()
|
|
||||||
.get_state(network_id)?;
|
|
||||||
|
|
||||||
// Release the address from the network
|
// Release the address from the network
|
||||||
match address {
|
match address {
|
||||||
@ -395,9 +383,7 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Update the network state
|
// Update the network state
|
||||||
gsm_inner
|
gsm_inner.network_states_mut().set_state(network_state);
|
||||||
.network_states_mut()
|
|
||||||
.set_state(network_state);
|
|
||||||
|
|
||||||
// Remove the address from the interface
|
// Remove the address from the interface
|
||||||
let addrs: Vec<_> = machine_state_interface
|
let addrs: Vec<_> = machine_state_interface
|
||||||
@ -479,9 +465,7 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the network state
|
// Get the network state
|
||||||
let mut network_state = gsm_inner
|
let mut network_state = gsm_inner.network_states().get_state(network_id)?;
|
||||||
.network_states()
|
|
||||||
.get_state(network_id)?;
|
|
||||||
|
|
||||||
// Release the addresses from the network
|
// Release the addresses from the network
|
||||||
for addr in &machine_state_interface.network_interface.addrs {
|
for addr in &machine_state_interface.network_interface.addrs {
|
||||||
@ -492,9 +476,7 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the network state
|
// Update the network state
|
||||||
gsm_inner
|
gsm_inner.network_states_mut().set_state(network_state);
|
||||||
.network_states_mut()
|
|
||||||
.set_state(network_state);
|
|
||||||
|
|
||||||
// Remove the addresses from the interface
|
// Remove the addresses from the interface
|
||||||
let mut new_intf = (*machine_state_interface.network_interface).clone();
|
let mut new_intf = (*machine_state_interface.network_interface).clone();
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
|
mod blueprint_locations_list;
|
||||||
mod blueprint_state;
|
mod blueprint_state;
|
||||||
mod machine_locations_list;
|
|
||||||
mod machine_state;
|
mod machine_state;
|
||||||
mod network_locations_list;
|
|
||||||
mod network_state;
|
mod network_state;
|
||||||
mod profile_state;
|
mod profile_state;
|
||||||
mod state_registry;
|
mod state_registry;
|
||||||
|
mod template_locations_list;
|
||||||
mod template_state;
|
mod template_state;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub use blueprint_locations_list::*;
|
||||||
pub use blueprint_state::*;
|
pub use blueprint_state::*;
|
||||||
pub use machine_locations_list::*;
|
|
||||||
pub use machine_state::*;
|
pub use machine_state::*;
|
||||||
pub use network_locations_list::*;
|
|
||||||
pub use network_state::*;
|
pub use network_state::*;
|
||||||
pub use profile_state::*;
|
pub use profile_state::*;
|
||||||
pub use state_registry::*;
|
pub use state_registry::*;
|
||||||
|
pub use template_locations_list::*;
|
||||||
pub use template_state::*;
|
pub use template_state::*;
|
||||||
|
@ -1,243 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
/// Locations where a network can be instantiated
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum NetworkLocationsList {
|
|
||||||
/// Network will be a new allocation
|
|
||||||
Allocations { allocations: WeightedList<String> },
|
|
||||||
/// Network will be allocated as a subnet of an existing network
|
|
||||||
Networks {
|
|
||||||
networks: WeightedList<NetworkStateId>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct NetworkLocation<T> {
|
|
||||||
pub scope: Vec<T>,
|
|
||||||
pub reserve: Vec<T>,
|
|
||||||
pub super_net: Option<NetworkStateId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetworkLocationsList {
|
|
||||||
pub fn pick_v4(
|
|
||||||
&self,
|
|
||||||
gsm_inner: &mut GlobalStateManagerInner,
|
|
||||||
prefix: &WeightedList<u8>,
|
|
||||||
) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv4Net>>> {
|
|
||||||
// Get maximum prefix
|
|
||||||
let max_prefix = prefix
|
|
||||||
.iter()
|
|
||||||
.max()
|
|
||||||
.copied()
|
|
||||||
.expect("must have at least one element");
|
|
||||||
|
|
||||||
// Get addresses for network
|
|
||||||
match self {
|
|
||||||
NetworkLocationsList::Allocations { allocations } => {
|
|
||||||
// Get allocations which have subnets that would fit
|
|
||||||
// our maximum requested prefix
|
|
||||||
let Some(address_pools) = allocations.try_filter_map(|allocation_name| {
|
|
||||||
let allocation = gsm_inner
|
|
||||||
.allocations()
|
|
||||||
.get(allocation_name)
|
|
||||||
.expect("must exist");
|
|
||||||
if allocation.address_pool.can_allocate_v4(max_prefix)? {
|
|
||||||
Ok(Some(allocation.address_pool.clone()))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pick an address pool
|
|
||||||
let mut address_pool = gsm_inner.srng().weighted_choice(address_pools);
|
|
||||||
|
|
||||||
// Pick a prefix length that would fit in the subnet
|
|
||||||
let opt_subnet = prefix
|
|
||||||
.try_filter(|p| address_pool.can_allocate_v4(*p))?
|
|
||||||
.as_ref()
|
|
||||||
.map(|wl| {
|
|
||||||
let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
|
|
||||||
|
|
||||||
address_pool.allocate_random_v4(gsm_inner.srng(), subnet_prefix, ())
|
|
||||||
})
|
|
||||||
.transpose()?
|
|
||||||
.flatten();
|
|
||||||
let Some(subnet) = opt_subnet else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
Ok(Some(NetworkLocation {
|
|
||||||
scope: vec![subnet],
|
|
||||||
reserve: Vec::new(),
|
|
||||||
super_net: None,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
NetworkLocationsList::Networks { networks } => {
|
|
||||||
// Get networks which have subnets that would fit
|
|
||||||
// our maximum requested prefix
|
|
||||||
let Some(available_networks) = networks.try_filter(|network_id| {
|
|
||||||
let super_network_state = gsm_inner
|
|
||||||
.network_states()
|
|
||||||
.get_state(*network_id)
|
|
||||||
.expect("must exist");
|
|
||||||
|
|
||||||
Ok(super_network_state.can_allocate_subnet_v4(None, max_prefix))
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pick a network
|
|
||||||
let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks);
|
|
||||||
let mut super_network_state = gsm_inner
|
|
||||||
.network_states()
|
|
||||||
.get_state(super_network_id)
|
|
||||||
.expect("must exist");
|
|
||||||
|
|
||||||
// Pick a prefix that fits in this network and allocate from it
|
|
||||||
let opt_subnet = prefix
|
|
||||||
.filter(|p| super_network_state.can_allocate_subnet_v4(None, *p))
|
|
||||||
.as_ref()
|
|
||||||
.map(|wl| {
|
|
||||||
let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
|
|
||||||
|
|
||||||
// Allocate subnet from this network
|
|
||||||
super_network_state.allocate_subnet_v4(
|
|
||||||
gsm_inner,
|
|
||||||
OwnerTag::Network(super_network_state.id()),
|
|
||||||
None,
|
|
||||||
subnet_prefix,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.transpose()?;
|
|
||||||
let Some(subnet) = opt_subnet else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update network state
|
|
||||||
gsm_inner
|
|
||||||
.network_states_mut()
|
|
||||||
.set_state(super_network_state);
|
|
||||||
|
|
||||||
Ok(Some(NetworkLocation {
|
|
||||||
scope: vec![subnet],
|
|
||||||
reserve: Vec::new(),
|
|
||||||
super_net: Some(super_network_id),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pick_v6(
|
|
||||||
&self,
|
|
||||||
gsm_inner: &mut GlobalStateManagerInner,
|
|
||||||
prefix: &WeightedList<u8>,
|
|
||||||
) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv6Net>>> {
|
|
||||||
// Get maximum prefix
|
|
||||||
let max_prefix = prefix
|
|
||||||
.iter()
|
|
||||||
.max()
|
|
||||||
.copied()
|
|
||||||
.expect("must have at least one element");
|
|
||||||
|
|
||||||
// Get addresses for network
|
|
||||||
match self {
|
|
||||||
NetworkLocationsList::Allocations { allocations } => {
|
|
||||||
// Get allocations which have subnets that would fit
|
|
||||||
// our maximum requested prefix
|
|
||||||
let Some(address_pools) = allocations.try_filter_map(|allocation_name| {
|
|
||||||
let allocation = gsm_inner
|
|
||||||
.allocations()
|
|
||||||
.get(allocation_name)
|
|
||||||
.expect("must exist");
|
|
||||||
if allocation.address_pool.can_allocate_v6(max_prefix)? {
|
|
||||||
Ok(Some(allocation.address_pool.clone()))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pick an address pool
|
|
||||||
let mut address_pool = gsm_inner.srng().weighted_choice(address_pools);
|
|
||||||
|
|
||||||
// Pick a prefix length that would fit in the subnet
|
|
||||||
let opt_subnet = prefix
|
|
||||||
.try_filter(|p| address_pool.can_allocate_v6(*p))?
|
|
||||||
.as_ref()
|
|
||||||
.map(|wl| {
|
|
||||||
let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
|
|
||||||
|
|
||||||
address_pool.allocate_random_v6(gsm_inner.srng(), subnet_prefix, ())
|
|
||||||
})
|
|
||||||
.transpose()?
|
|
||||||
.flatten();
|
|
||||||
let Some(subnet) = opt_subnet else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
Ok(Some(NetworkLocation {
|
|
||||||
scope: vec![subnet],
|
|
||||||
reserve: Vec::new(),
|
|
||||||
super_net: None,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
NetworkLocationsList::Networks { networks } => {
|
|
||||||
// Get networks which have subnets that would fit
|
|
||||||
// our maximum requested prefix
|
|
||||||
let Some(available_networks) = networks.try_filter(|network_id| {
|
|
||||||
let super_network_state = gsm_inner
|
|
||||||
.network_states()
|
|
||||||
.get_state(*network_id)
|
|
||||||
.expect("must exist");
|
|
||||||
|
|
||||||
Ok(super_network_state.can_allocate_subnet_v6(None, max_prefix))
|
|
||||||
})?
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pick a network
|
|
||||||
let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks);
|
|
||||||
let mut super_network_state = gsm_inner
|
|
||||||
.network_states()
|
|
||||||
.get_state(super_network_id)
|
|
||||||
.expect("must exist");
|
|
||||||
|
|
||||||
// Pick a prefix that fits in this network and allocate from it
|
|
||||||
let opt_subnet = prefix
|
|
||||||
.filter(|p| super_network_state.can_allocate_subnet_v6(None, *p))
|
|
||||||
.as_ref()
|
|
||||||
.map(|wl| {
|
|
||||||
let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl);
|
|
||||||
|
|
||||||
// Allocate subnet from this network
|
|
||||||
super_network_state.allocate_subnet_v6(
|
|
||||||
gsm_inner,
|
|
||||||
OwnerTag::Network(super_network_state.id()),
|
|
||||||
None,
|
|
||||||
subnet_prefix,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.transpose()?;
|
|
||||||
let Some(subnet) = opt_subnet else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update network state
|
|
||||||
gsm_inner
|
|
||||||
.network_states_mut()
|
|
||||||
.set_state(super_network_state);
|
|
||||||
|
|
||||||
Ok(Some(NetworkLocation {
|
|
||||||
scope: vec![subnet],
|
|
||||||
reserve: Vec::new(),
|
|
||||||
super_net: Some(super_network_id),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ pub enum OwnerTag {
|
|||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum NetworkOrigin {
|
pub enum NetworkOrigin {
|
||||||
InitialConfig,
|
Config,
|
||||||
Direct,
|
Direct,
|
||||||
Blueprint(BlueprintStateId),
|
Blueprint(BlueprintStateId),
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ struct PerNetworkInfo {
|
|||||||
struct TemplateStateFields {
|
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<TemplateLocationsList>,
|
||||||
machines: imbl::HashSet<MachineStateId>,
|
machines: imbl::HashSet<MachineStateId>,
|
||||||
machines_per_network: imbl::HashMap<NetworkStateId, PerNetworkInfo>,
|
machines_per_network: imbl::HashMap<NetworkStateId, PerNetworkInfo>,
|
||||||
disable_capabilities: imbl::Vector<Arc<String>>,
|
disable_capabilities: imbl::Vector<Arc<String>>,
|
||||||
@ -58,7 +58,7 @@ impl TemplateState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_networks_list(&mut self, networks: WeightedList<NetworkStateId>) {
|
pub fn set_networks_list(&mut self, networks: WeightedList<NetworkStateId>) {
|
||||||
let locations_list = Some(MachineLocationsList::Networks { networks });
|
let locations_list = Some(TemplateLocationsList::Networks { networks });
|
||||||
|
|
||||||
// Update fields
|
// Update fields
|
||||||
self.fields = Arc::new(TemplateStateFields {
|
self.fields = Arc::new(TemplateStateFields {
|
||||||
@ -67,8 +67,8 @@ impl TemplateState {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_blueprints_list(mut self, blueprints: WeightedList<BlueprintStateId>) {
|
pub fn set_blueprints_list(&mut self, blueprints: WeightedList<BlueprintStateId>) {
|
||||||
let locations_list = Some(MachineLocationsList::Blueprints { blueprints });
|
let locations_list = Some(TemplateLocationsList::Blueprints { blueprints });
|
||||||
|
|
||||||
// Update fields
|
// Update fields
|
||||||
self.fields = Arc::new(TemplateStateFields {
|
self.fields = Arc::new(TemplateStateFields {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user