feat: automatically delete expired vms on client

This commit is contained in:
2025-03-31 12:19:41 +01:00
parent 36069bb6a7
commit 97d631ce5d
4 changed files with 63 additions and 8 deletions

View File

@ -45,6 +45,9 @@ pub trait VmHostClient: Send + Sync {
/// Spawn a VM
async fn create_vm(&self, cfg: &FullVmInfo) -> Result<()>;
/// Delete a VM
async fn delete_vm(&self, vm: &Vm) -> Result<()>;
/// Re-install a vm OS
async fn reinstall_vm(&self, cfg: &FullVmInfo) -> Result<()>;

View File

@ -611,6 +611,32 @@ impl VmHostClient for ProxmoxClient {
Ok(())
}
async fn delete_vm(&self, vm: &Vm) -> Result<()> {
let vm_id: ProxmoxVmId = vm.id.into();
// NOT IMPLEMENTED
//let t = self.delete_vm(&self.node, vm_id).await?;
//self.wait_for_task(&t).await?;
if let Some(ssh) = &self.ssh {
let mut ses = SshClient::new()?;
ses.connect(
(self.api.base().host().unwrap().to_string(), 22),
&ssh.user,
&ssh.key,
)
.await?;
let cmd = format!("/usr/sbin/qm destroy {}", vm_id,);
let (code, rsp) = ses.execute(cmd.as_str()).await?;
info!("{}", rsp);
if code != 0 {
bail!("Failed to destroy vm, exit-code {}, {}", code, rsp);
}
}
Ok(())
}
async fn reinstall_vm(&self, req: &FullVmInfo) -> Result<()> {
let vm_id = req.vm.id.into();
@ -1198,7 +1224,7 @@ mod tests {
enabled: true,
release_date: Utc::now(),
url: "http://localhost.com/ubuntu_server_24.04.img".to_string(),
default_username: None
default_username: None,
},
ips: vec![
VmIpAssignment {

View File

@ -1,14 +1,21 @@
#![allow(unused)]
use crate::dns::{BasicRecord, DnsServer, RecordType};
use crate::exchange::{ExchangeRateService, Ticker, TickerRate};
use crate::host::{FullVmInfo, TerminalStream, TimeSeries, TimeSeriesData, VmHostClient, VmHostInfo};
use crate::host::{
FullVmInfo, TerminalStream, TimeSeries, TimeSeriesData, VmHostClient, VmHostInfo,
};
use crate::lightning::{AddInvoiceRequest, AddInvoiceResult, InvoiceUpdate, LightningNode};
use crate::router::{ArpEntry, Router};
use crate::status::{VmRunningState, VmState};
use anyhow::{anyhow, bail, ensure, Context};
use chrono::{DateTime, TimeDelta, Utc};
use fedimint_tonic_lnd::tonic::codegen::tokio_stream::Stream;
use lnvps_db::{async_trait, AccessPolicy, DiskInterface, DiskType, IpRange, IpRangeAllocationMode, LNVpsDb, OsDistribution, User, UserSshKey, Vm, VmCostPlan, VmCostPlanIntervalType, VmCustomPricing, VmCustomPricingDisk, VmCustomTemplate, VmHost, VmHostDisk, VmHostKind, VmHostRegion, VmIpAssignment, VmOsImage, VmPayment, VmTemplate};
use lnvps_db::{
async_trait, AccessPolicy, DiskInterface, DiskType, IpRange, IpRangeAllocationMode, LNVpsDb,
OsDistribution, User, UserSshKey, Vm, VmCostPlan, VmCostPlanIntervalType, VmCustomPricing,
VmCustomPricingDisk, VmCustomTemplate, VmHost, VmHostDisk, VmHostKind, VmHostRegion,
VmIpAssignment, VmOsImage, VmPayment, VmTemplate,
};
use std::collections::HashMap;
use std::ops::Add;
use std::pin::Pin;
@ -174,7 +181,7 @@ impl Default for MockDb {
enabled: true,
release_date: Utc::now(),
url: "https://example.com/debian_12.img".to_string(),
default_username: None
default_username: None,
},
);
Self {
@ -828,6 +835,12 @@ impl VmHostClient for MockVmHost {
Ok(())
}
async fn delete_vm(&self, vm: &Vm) -> anyhow::Result<()> {
let mut vms = self.vms.lock().await;
vms.remove(&vm.id);
Ok(())
}
async fn reinstall_vm(&self, cfg: &FullVmInfo) -> anyhow::Result<()> {
todo!()
}
@ -898,7 +911,10 @@ impl DnsServer for MockDnsServer {
zones.get_mut(zone_id).unwrap()
};
if table.values().any(|v| v.name == record.name && v.kind == record.kind.to_string()) {
if table
.values()
.any(|v| v.name == record.name && v.kind == record.kind.to_string())
{
bail!("Duplicate record with name {}", record.name);
}

View File

@ -593,8 +593,13 @@ impl LNVpsProvisioner {
/// Delete a VM and its associated resources
pub async fn delete_vm(&self, vm_id: u64) -> Result<()> {
// host client currently doesn't support delete (proxmox)
// VM should already be stopped by [Worker]
let vm = self.db.get_vm(vm_id).await?;
let host = self.db.get_host(vm.host_id).await?;
let client = get_host_client(&host, &self.provisioner_config)?;
if let Err(e) = client.delete_vm(&vm).await {
warn!("Failed to delete VM: {}", e);
}
self.delete_ip_assignments(vm_id).await?;
self.db.delete_vm(vm_id).await?;
@ -762,7 +767,12 @@ mod tests {
assert_eq!(zones.get("mock-v6-rev-zone-id").unwrap().len(), 1);
assert_eq!(zones.get("mock-forward-zone-id").unwrap().len(), 2);
let v6 = zones.get("mock-v6-rev-zone-id").unwrap().iter().next().unwrap();
let v6 = zones
.get("mock-v6-rev-zone-id")
.unwrap()
.iter()
.next()
.unwrap();
assert_eq!(v6.1.kind, "PTR");
assert!(v6.1.name.ends_with("0.0.d.f.ip6.arpa"));
}