feat: get host for template

feat: apply load factor
This commit is contained in:
2025-03-05 13:25:27 +00:00
parent 2bd6b5f09f
commit a212ed661a
9 changed files with 273 additions and 84 deletions

View File

@ -2,7 +2,9 @@ use crate::dns::{BasicRecord, DnsServer};
use crate::exchange::{ExchangeRateService, Ticker};
use crate::host::{get_host_client, FullVmInfo};
use crate::lightning::{AddInvoiceRequest, LightningNode};
use crate::provisioner::{NetworkProvisioner, ProvisionerMethod};
use crate::provisioner::{
HostCapacity, HostCapacityService, NetworkProvisioner, ProvisionerMethod,
};
use crate::router::{ArpEntry, Router};
use crate::settings::{NetworkAccessPolicy, NetworkPolicy, ProvisionerConfig, Settings};
use anyhow::{bail, ensure, Context, Result};
@ -255,33 +257,28 @@ impl LNVpsProvisioner {
let template = self.db.get_vm_template(template_id).await?;
let image = self.db.get_os_image(image_id).await?;
let ssh_key = self.db.get_user_ssh_key(ssh_key_id).await?;
let hosts = self.db.list_hosts().await?;
// TODO: impl resource usage based provisioning
let pick_host = if let Some(h) = hosts.first() {
h
} else {
bail!("No host found")
};
// TODO: impl resource usage based provisioning (disk)
let host_disks = self.db.list_host_disks(pick_host.id).await?;
let pick_disk = if let Some(hd) = host_disks.first() {
// TODO: cache capacity somewhere
let cap = HostCapacityService::new(self.db.clone());
let host = cap.get_host_for_template(&template).await?;
let pick_disk = if let Some(hd) = host.disks.first() {
hd
} else {
bail!("No host disk found")
};
let client = get_host_client(&pick_host, &self.provisioner_config)?;
let client = get_host_client(&host.host, &self.provisioner_config)?;
let mut new_vm = Vm {
id: 0,
host_id: pick_host.id,
host_id: host.host.id,
user_id: user.id,
image_id: image.id,
template_id: template.id,
ssh_key_id: ssh_key.id,
created: Utc::now(),
expires: Utc::now(),
disk_id: pick_disk.id,
disk_id: pick_disk.disk.id,
mac_address: "NOT FILLED YET".to_string(),
deleted: false,
ref_code,
@ -406,13 +403,14 @@ mod tests {
use crate::exchange::DefaultRateCache;
use crate::mocks::{MockDb, MockDnsServer, MockNode, MockRouter};
use crate::settings::{DnsServerConfig, LightningConfig, QemuConfig, RouterConfig};
use lnvps_db::UserSshKey;
use lnvps_db::{DiskInterface, DiskType, User, UserSshKey, VmTemplate};
#[tokio::test]
async fn test_basic_provisioner() -> Result<()> {
const ROUTER_BRIDGE: &str = "bridge1";
const ROUTER_BRIDGE: &str = "bridge1";
const GB: u64 = 1024 * 1024 * 1024;
const TB: u64 = GB * 1024;
let settings = Settings {
fn settings() -> Settings {
Settings {
listen: None,
db: "".to_string(),
lightning: LightningConfig::LND {
@ -452,18 +450,14 @@ mod tests {
reverse_zone_id: "456".to_string(),
}),
nostr: None,
};
let db = Arc::new(MockDb::default());
let node = Arc::new(MockNode::default());
let rates = Arc::new(DefaultRateCache::default());
let router = MockRouter::new(settings.network_policy.clone());
let dns = MockDnsServer::new();
let provisioner = LNVpsProvisioner::new(settings, db.clone(), node.clone(), rates.clone());
}
}
async fn add_user(db: &Arc<MockDb>) -> Result<(User, UserSshKey)> {
let pubkey: [u8; 32] = random();
let user_id = db.upsert_user(&pubkey).await?;
let new_key = UserSshKey {
let mut new_key = UserSshKey {
id: 0,
name: "test-key".to_string(),
user_id,
@ -471,9 +465,23 @@ mod tests {
key_data: "ssh-rsa AAA==".to_string(),
};
let ssh_key = db.insert_user_ssh_key(&new_key).await?;
new_key.id = ssh_key;
Ok((db.get_user(user_id).await?, new_key))
}
#[tokio::test]
async fn basic() -> Result<()> {
let settings = settings();
let db = Arc::new(MockDb::default());
let node = Arc::new(MockNode::default());
let rates = Arc::new(DefaultRateCache::default());
let router = MockRouter::new(settings.network_policy.clone());
let dns = MockDnsServer::new();
let provisioner = LNVpsProvisioner::new(settings, db.clone(), node.clone(), rates.clone());
let (user, ssh_key) = add_user(&db).await?;
let vm = provisioner
.provision(user_id, 1, 1, ssh_key, Some("mock-ref".to_string()))
.provision(user.id, 1, 1, ssh_key.id, Some("mock-ref".to_string()))
.await?;
println!("{:?}", vm);
provisioner.spawn_vm(vm.id).await?;
@ -527,4 +535,39 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn test_no_capacity() -> Result<()> {
let settings = settings();
let db = Arc::new(MockDb::default());
let node = Arc::new(MockNode::default());
let rates = Arc::new(DefaultRateCache::default());
let prov = LNVpsProvisioner::new(settings.clone(), db.clone(), node.clone(), rates.clone());
let large_template = VmTemplate {
id: 0,
name: "mock-large-template".to_string(),
enabled: true,
created: Default::default(),
expires: None,
cpu: 64,
memory: 512 * GB,
disk_size: 20 * TB,
disk_type: DiskType::SSD,
disk_interface: DiskInterface::PCIe,
cost_plan_id: 1,
region_id: 1,
};
let id = db.insert_vm_template(&large_template).await?;
let (user, ssh_key) = add_user(&db).await?;
let prov = prov.provision(user.id, id, 1, ssh_key.id, None).await;
assert!(prov.is_err());
if let Err(e) = prov {
println!("{}", e);
assert!(e.to_string().to_lowercase().contains("no available host"))
}
Ok(())
}
}