feat: automatically delete expired vms on client
This commit is contained in:
@ -45,6 +45,9 @@ pub trait VmHostClient: Send + Sync {
|
|||||||
/// Spawn a VM
|
/// Spawn a VM
|
||||||
async fn create_vm(&self, cfg: &FullVmInfo) -> Result<()>;
|
async fn create_vm(&self, cfg: &FullVmInfo) -> Result<()>;
|
||||||
|
|
||||||
|
/// Delete a VM
|
||||||
|
async fn delete_vm(&self, vm: &Vm) -> Result<()>;
|
||||||
|
|
||||||
/// Re-install a vm OS
|
/// Re-install a vm OS
|
||||||
async fn reinstall_vm(&self, cfg: &FullVmInfo) -> Result<()>;
|
async fn reinstall_vm(&self, cfg: &FullVmInfo) -> Result<()>;
|
||||||
|
|
||||||
|
@ -611,6 +611,32 @@ impl VmHostClient for ProxmoxClient {
|
|||||||
Ok(())
|
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<()> {
|
async fn reinstall_vm(&self, req: &FullVmInfo) -> Result<()> {
|
||||||
let vm_id = req.vm.id.into();
|
let vm_id = req.vm.id.into();
|
||||||
|
|
||||||
@ -1198,7 +1224,7 @@ mod tests {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
release_date: Utc::now(),
|
release_date: Utc::now(),
|
||||||
url: "http://localhost.com/ubuntu_server_24.04.img".to_string(),
|
url: "http://localhost.com/ubuntu_server_24.04.img".to_string(),
|
||||||
default_username: None
|
default_username: None,
|
||||||
},
|
},
|
||||||
ips: vec![
|
ips: vec![
|
||||||
VmIpAssignment {
|
VmIpAssignment {
|
||||||
|
24
src/mocks.rs
24
src/mocks.rs
@ -1,14 +1,21 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use crate::dns::{BasicRecord, DnsServer, RecordType};
|
use crate::dns::{BasicRecord, DnsServer, RecordType};
|
||||||
use crate::exchange::{ExchangeRateService, Ticker, TickerRate};
|
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::lightning::{AddInvoiceRequest, AddInvoiceResult, InvoiceUpdate, LightningNode};
|
||||||
use crate::router::{ArpEntry, Router};
|
use crate::router::{ArpEntry, Router};
|
||||||
use crate::status::{VmRunningState, VmState};
|
use crate::status::{VmRunningState, VmState};
|
||||||
use anyhow::{anyhow, bail, ensure, Context};
|
use anyhow::{anyhow, bail, ensure, Context};
|
||||||
use chrono::{DateTime, TimeDelta, Utc};
|
use chrono::{DateTime, TimeDelta, Utc};
|
||||||
use fedimint_tonic_lnd::tonic::codegen::tokio_stream::Stream;
|
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::collections::HashMap;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@ -174,7 +181,7 @@ impl Default for MockDb {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
release_date: Utc::now(),
|
release_date: Utc::now(),
|
||||||
url: "https://example.com/debian_12.img".to_string(),
|
url: "https://example.com/debian_12.img".to_string(),
|
||||||
default_username: None
|
default_username: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Self {
|
Self {
|
||||||
@ -828,6 +835,12 @@ impl VmHostClient for MockVmHost {
|
|||||||
Ok(())
|
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<()> {
|
async fn reinstall_vm(&self, cfg: &FullVmInfo) -> anyhow::Result<()> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@ -898,7 +911,10 @@ impl DnsServer for MockDnsServer {
|
|||||||
zones.get_mut(zone_id).unwrap()
|
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);
|
bail!("Duplicate record with name {}", record.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,8 +593,13 @@ impl LNVpsProvisioner {
|
|||||||
|
|
||||||
/// Delete a VM and its associated resources
|
/// Delete a VM and its associated resources
|
||||||
pub async fn delete_vm(&self, vm_id: u64) -> Result<()> {
|
pub async fn delete_vm(&self, vm_id: u64) -> Result<()> {
|
||||||
// host client currently doesn't support delete (proxmox)
|
let vm = self.db.get_vm(vm_id).await?;
|
||||||
// VM should already be stopped by [Worker]
|
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.delete_ip_assignments(vm_id).await?;
|
||||||
self.db.delete_vm(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-v6-rev-zone-id").unwrap().len(), 1);
|
||||||
assert_eq!(zones.get("mock-forward-zone-id").unwrap().len(), 2);
|
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_eq!(v6.1.kind, "PTR");
|
||||||
assert!(v6.1.name.ends_with("0.0.d.f.ip6.arpa"));
|
assert!(v6.1.name.ends_with("0.0.d.f.ip6.arpa"));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user