fix: ip assigment index feat: default username
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -4691,8 +4691,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
[[package]]
|
||||
name = "virt"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a05f77c836efa9be343b5419663cf829d75203b813579993cdd9c44f51767e"
|
||||
source = "git+https://gitlab.com/libvirt/libvirt-rust.git#70394aad4d9597c9ff87c0ada6711ed4f9528991"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"uuid",
|
||||
@ -4702,8 +4701,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "virt-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c504e459878f09177f41bf2f8bb3e9a8af4fca7a09e73152fee02535d501601c"
|
||||
source = "git+https://gitlab.com/libvirt/libvirt-rust.git#70394aad4d9597c9ff87c0ada6711ed4f9528991"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
|
14
Cargo.toml
14
Cargo.toml
@ -7,7 +7,17 @@ edition = "2021"
|
||||
name = "api"
|
||||
|
||||
[features]
|
||||
default = ["mikrotik", "nostr-dm", "nostr-dvm", "proxmox", "lnd", "cloudflare", "revolut", "bitvora"]
|
||||
default = [
|
||||
"mikrotik",
|
||||
"nostr-dm",
|
||||
"nostr-dvm",
|
||||
"proxmox",
|
||||
"lnd",
|
||||
"cloudflare",
|
||||
"revolut",
|
||||
"bitvora",
|
||||
"libvirt"
|
||||
]
|
||||
mikrotik = ["dep:reqwest"]
|
||||
nostr-dm = ["dep:nostr-sdk"]
|
||||
nostr-dvm = ["dep:nostr-sdk"]
|
||||
@ -53,7 +63,7 @@ ssh2 = { version = "0.9.4", optional = true }
|
||||
reqwest = { version = "0.12.8", optional = true }
|
||||
|
||||
#libvirt
|
||||
virt = { version = "0.4.2", optional = true }
|
||||
virt = { git = "https://gitlab.com/libvirt/libvirt-rust.git", optional = true }
|
||||
|
||||
#lnd
|
||||
fedimint-tonic-lnd = { version = "0.2.0", default-features = false, features = ["invoicesrpc"], optional = true }
|
||||
|
4
lnvps_db/migrations/20250328220956_fixes.sql
Normal file
4
lnvps_db/migrations/20250328220956_fixes.sql
Normal file
@ -0,0 +1,4 @@
|
||||
-- Add migration script here
|
||||
ALTER TABLE vm_ip_assignment DROP KEY ix_vm_ip_assignment_ip;
|
||||
alter table vm_os_image
|
||||
add column default_username varchar(50);
|
@ -206,6 +206,7 @@ pub struct VmOsImage {
|
||||
pub release_date: DateTime<Utc>,
|
||||
/// URL location of cloud image
|
||||
pub url: String,
|
||||
pub default_username: Option<String>,
|
||||
}
|
||||
|
||||
impl VmOsImage {
|
||||
|
@ -455,6 +455,7 @@ pub struct ApiVmOsImage {
|
||||
pub flavour: String,
|
||||
pub version: String,
|
||||
pub release_date: DateTime<Utc>,
|
||||
pub default_username: Option<String>,
|
||||
}
|
||||
|
||||
impl From<lnvps_db::VmOsImage> for ApiVmOsImage {
|
||||
@ -465,6 +466,7 @@ impl From<lnvps_db::VmOsImage> for ApiVmOsImage {
|
||||
flavour: image.flavour,
|
||||
version: image.version,
|
||||
release_date: image.release_date,
|
||||
default_username: image.default_username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use anyhow::{bail, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
use nostr::Url;
|
||||
use reqwest::header::AUTHORIZATION;
|
||||
use reqwest::{Client, Method, RequestBuilder};
|
||||
use reqwest::{Method, RequestBuilder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
@ -1,44 +1,99 @@
|
||||
use crate::host::{FullVmInfo, TimeSeries, TimeSeriesData, VmHostClient};
|
||||
use crate::status::VmState;
|
||||
use crate::host::{
|
||||
FullVmInfo, TerminalStream, TimeSeries, TimeSeriesData, VmHostClient, VmHostDiskInfo,
|
||||
VmHostInfo,
|
||||
};
|
||||
use crate::settings::QemuConfig;
|
||||
use crate::status::{VmRunningState, VmState};
|
||||
use crate::KB;
|
||||
use anyhow::{Context, Result};
|
||||
use chrono::Utc;
|
||||
use lnvps_db::{async_trait, Vm, VmOsImage};
|
||||
use virt::connect::Connect;
|
||||
use virt::domain::Domain;
|
||||
use virt::sys::{virDomainCreate, VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE};
|
||||
|
||||
pub struct LibVirt {}
|
||||
#[derive(Debug)]
|
||||
pub struct LibVirtHost {
|
||||
connection: Connect,
|
||||
qemu: QemuConfig,
|
||||
}
|
||||
|
||||
impl LibVirtHost {
|
||||
pub fn new(url: &str, qemu: QemuConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
connection: Connect::open(Some(url))?,
|
||||
qemu,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl VmHostClient for LibVirt {
|
||||
async fn download_os_image(&self, image: &VmOsImage) -> anyhow::Result<()> {
|
||||
impl VmHostClient for LibVirtHost {
|
||||
async fn get_info(&self) -> Result<VmHostInfo> {
|
||||
let info = self.connection.get_node_info()?;
|
||||
let storage = self
|
||||
.connection
|
||||
.list_all_storage_pools(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)?;
|
||||
Ok(VmHostInfo {
|
||||
cpu: info.cpus as u16,
|
||||
memory: info.memory * KB,
|
||||
disks: storage
|
||||
.iter()
|
||||
.filter_map(|p| {
|
||||
let info = p.get_info().ok()?;
|
||||
Some(VmHostDiskInfo {
|
||||
name: p.get_name().context("storage pool name is missing").ok()?,
|
||||
size: info.capacity,
|
||||
used: info.allocation,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn download_os_image(&self, image: &VmOsImage) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn generate_mac(&self, vm: &Vm) -> Result<String> {
|
||||
Ok("ff:ff:ff:ff:ff:ff".to_string())
|
||||
}
|
||||
|
||||
async fn start_vm(&self, vm: &Vm) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn stop_vm(&self, vm: &Vm) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn reset_vm(&self, vm: &Vm) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_vm(&self, cfg: &FullVmInfo) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn reinstall_vm(&self, cfg: &FullVmInfo) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn generate_mac(&self, vm: &Vm) -> anyhow::Result<String> {
|
||||
todo!()
|
||||
async fn get_vm_state(&self, vm: &Vm) -> Result<VmState> {
|
||||
Ok(VmState {
|
||||
timestamp: Utc::now().timestamp() as u64,
|
||||
state: VmRunningState::Stopped,
|
||||
cpu_usage: 0.0,
|
||||
mem_usage: 0.0,
|
||||
uptime: 0,
|
||||
net_in: 0,
|
||||
net_out: 0,
|
||||
disk_write: 0,
|
||||
disk_read: 0,
|
||||
})
|
||||
}
|
||||
|
||||
async fn start_vm(&self, vm: &Vm) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn stop_vm(&self, vm: &Vm) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn reset_vm(&self, vm: &Vm) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn create_vm(&self, cfg: &FullVmInfo) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn reinstall_vm(&self, cfg: &FullVmInfo) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_vm_state(&self, vm: &Vm) -> anyhow::Result<VmState> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn configure_vm(&self, vm: &FullVmInfo) -> anyhow::Result<()> {
|
||||
async fn configure_vm(&self, vm: &FullVmInfo) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
@ -46,7 +101,11 @@ impl VmHostClient for LibVirt {
|
||||
&self,
|
||||
vm: &Vm,
|
||||
series: TimeSeries,
|
||||
) -> anyhow::Result<Vec<TimeSeriesData>> {
|
||||
) -> Result<Vec<TimeSeriesData>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn connect_terminal(&self, vm: &Vm) -> Result<TerminalStream> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
|
||||
//#[cfg(feature = "libvirt")]
|
||||
//mod libvirt;
|
||||
#[cfg(feature = "libvirt")]
|
||||
mod libvirt;
|
||||
#[cfg(feature = "proxmox")]
|
||||
mod proxmox;
|
||||
|
||||
@ -67,31 +67,28 @@ pub trait VmHostClient: Send + Sync {
|
||||
|
||||
pub fn get_host_client(host: &VmHost, cfg: &ProvisionerConfig) -> Result<Arc<dyn VmHostClient>> {
|
||||
#[cfg(test)]
|
||||
{
|
||||
Ok(Arc::new(crate::mocks::MockVmHost::new()))
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
Ok(match (host.kind.clone(), &cfg) {
|
||||
return Ok(Arc::new(crate::mocks::MockVmHost::new()));
|
||||
|
||||
Ok(match host.kind.clone() {
|
||||
#[cfg(feature = "proxmox")]
|
||||
(
|
||||
VmHostKind::Proxmox,
|
||||
ProvisionerConfig::Proxmox {
|
||||
qemu,
|
||||
ssh,
|
||||
mac_prefix,
|
||||
},
|
||||
) => Arc::new(proxmox::ProxmoxClient::new(
|
||||
VmHostKind::Proxmox if cfg.proxmox.is_some() => {
|
||||
let cfg = cfg.proxmox.clone().unwrap();
|
||||
Arc::new(proxmox::ProxmoxClient::new(
|
||||
host.ip.parse()?,
|
||||
&host.name,
|
||||
&host.api_token,
|
||||
mac_prefix.clone(),
|
||||
qemu.clone(),
|
||||
ssh.clone(),
|
||||
)),
|
||||
cfg.mac_prefix,
|
||||
cfg.qemu,
|
||||
cfg.ssh,
|
||||
))
|
||||
}
|
||||
#[cfg(feature = "libvirt")]
|
||||
VmHostKind::LibVirt if cfg.libvirt.is_some() => {
|
||||
let cfg = cfg.libvirt.clone().unwrap();
|
||||
Arc::new(libvirt::LibVirtHost::new(&host.ip, cfg.qemu)?)
|
||||
}
|
||||
_ => bail!("Unknown host config: {}", host.kind),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// All VM info necessary to provision a VM and its associated resources
|
||||
|
@ -1198,6 +1198,7 @@ mod tests {
|
||||
enabled: true,
|
||||
release_date: Utc::now(),
|
||||
url: "http://localhost.com/ubuntu_server_24.04.img".to_string(),
|
||||
default_username: None
|
||||
},
|
||||
ips: vec![
|
||||
VmIpAssignment {
|
||||
|
@ -104,16 +104,27 @@ pub struct SmtpConfig {
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum ProvisionerConfig {
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
Proxmox {
|
||||
pub struct ProvisionerConfig {
|
||||
pub proxmox: Option<ProxmoxConfig>,
|
||||
pub libvirt: Option<LibVirtConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct ProxmoxConfig {
|
||||
/// Generic VM configuration
|
||||
qemu: QemuConfig,
|
||||
pub qemu: QemuConfig,
|
||||
/// SSH config for issuing commands via CLI
|
||||
ssh: Option<SshConfig>,
|
||||
pub ssh: Option<SshConfig>,
|
||||
/// MAC address prefix for NIC (eg. bc:24:11)
|
||||
mac_prefix: Option<String>,
|
||||
},
|
||||
pub mac_prefix: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct LibVirtConfig {
|
||||
/// Generic VM configuration
|
||||
pub qemu: QemuConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
@ -198,7 +209,8 @@ pub fn mock_settings() -> Settings {
|
||||
macaroon: Default::default(),
|
||||
},
|
||||
read_only: false,
|
||||
provisioner: ProvisionerConfig::Proxmox {
|
||||
provisioner: ProvisionerConfig {
|
||||
proxmox: Some(ProxmoxConfig {
|
||||
qemu: QemuConfig {
|
||||
machine: "q35".to_string(),
|
||||
os_type: "l26".to_string(),
|
||||
@ -208,6 +220,8 @@ pub fn mock_settings() -> Settings {
|
||||
},
|
||||
ssh: None,
|
||||
mac_prefix: Some("ff:ff:ff".to_string()),
|
||||
}),
|
||||
libvirt: None,
|
||||
},
|
||||
delete_after: 0,
|
||||
smtp: None,
|
||||
|
Reference in New Issue
Block a user