use crate::config::BlueprintManagerConfig;
use crate::error::Result;
#[cfg(feature = "vm-sandbox")]
use crate::rt::hypervisor::net::NetworkManager;
use blueprint_auth::db::RocksDb;
use std::ops::{Deref, DerefMut};
use tokio::sync::Mutex;
#[cfg(feature = "containers")]
pub struct ContainerContext {
pub kube_client: Option<kube::Client>,
pub kube_service_port: Mutex<crate::sdk::utils::PortLock>,
pub local_ip: std::net::IpAddr,
}
#[cfg(feature = "vm-sandbox")]
pub struct VmContext {
pub network_manager: NetworkManager,
pub network_interface: String,
}
pub struct BlueprintManagerContext {
#[cfg(feature = "containers")]
pub containers: ContainerContext,
#[cfg(feature = "vm-sandbox")]
pub vm: VmContext,
pub(crate) db: Mutex<Option<RocksDb>>,
config: BlueprintManagerConfig,
#[cfg(feature = "remote-providers")]
cloud_config: Option<blueprint_remote_providers::CloudConfig>,
}
impl BlueprintManagerContext {
#[allow(clippy::unused_async)]
pub async fn new(mut config: BlueprintManagerConfig) -> Result<Self> {
config.paths.data_dir = std::path::absolute(config.data_dir())?;
config.verify_directories_exist()?;
#[cfg(feature = "vm-sandbox")]
let (network_manager, network_interface) = {
use blueprint_core::info;
let interface = config.verify_network_interface()?;
crate::rt::hypervisor::net::nftables::check_net_admin_capability()?;
let network_candidates = config
.vm_sandbox_options
.default_address_pool
.hosts()
.filter(|ip| ip.octets()[3] != 0 && ip.octets()[3] != 255)
.collect();
if config.vm_sandbox_options.no_vm {
info!("Skipping VM image check, running in no-vm mode");
} else {
info!("Checking for VM images");
crate::rt::hypervisor::images::download_image_if_needed(config.cache_dir()).await?;
}
(NetworkManager::new(network_candidates).await?, interface)
};
#[cfg(feature = "containers")]
let kube_client = match kube::Client::try_default().await {
Ok(client) => {
tracing::debug!("Successfully initialized Kubernetes client");
Some(client)
}
Err(e) => {
tracing::warn!(
"Failed to initialize Kubernetes client (container runtime will be unavailable): {}",
e
);
None
}
};
Ok(Self {
#[cfg(feature = "containers")]
containers: ContainerContext {
kube_client,
kube_service_port: Mutex::new(crate::sdk::utils::PortLock::lock(
config.kube_service_port(),
)?),
local_ip: local_ip_address::local_ip()?,
},
#[cfg(feature = "vm-sandbox")]
vm: VmContext {
network_manager,
network_interface,
},
db: Mutex::new(None),
#[cfg(feature = "remote-providers")]
cloud_config: Self::load_cloud_config(&config),
config,
})
}
pub async fn db(&self) -> Option<RocksDb> {
self.db.lock().await.clone()
}
pub async fn set_db(&self, db: RocksDb) {
self.db.lock().await.replace(db);
}
#[cfg(feature = "containers")]
pub async fn kube_service_port(&self) -> u16 {
let mut guard = self.containers.kube_service_port.lock().await;
guard.unlock()
}
#[cfg(feature = "remote-providers")]
pub fn cloud_config(&self) -> &Option<blueprint_remote_providers::CloudConfig> {
&self.cloud_config
}
#[cfg(feature = "remote-providers")]
fn load_cloud_config(
_config: &BlueprintManagerConfig,
) -> Option<blueprint_remote_providers::CloudConfig> {
blueprint_remote_providers::CloudConfig::from_env()
}
}
impl Deref for BlueprintManagerContext {
type Target = BlueprintManagerConfig;
fn deref(&self) -> &Self::Target {
&self.config
}
}
impl DerefMut for BlueprintManagerContext {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.config
}
}