feat: readonly mode

This commit is contained in:
kieran 2024-11-26 15:11:12 +00:00
parent 76241cc08b
commit e6c3b4e063
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
6 changed files with 31 additions and 16 deletions

View File

@ -1,5 +1,6 @@
# MySQL database connection string # MySQL database connection string
db: "mysql://root:root@localhost:3376/lnvps" db: "mysql://root:root@localhost:3376/lnvps"
read_only: true
lnd: lnd:
url: "https://127.0.0.1:10003" url: "https://127.0.0.1:10003"
cert: "/home/kieran/.polar/networks/2/volumes/lnd/alice/tls.cert" cert: "/home/kieran/.polar/networks/2/volumes/lnd/alice/tls.cert"

View File

@ -69,7 +69,11 @@ struct ApiVmStatus {
} }
#[get("/api/v1/vm")] #[get("/api/v1/vm")]
async fn v1_list_vms(auth: Nip98Auth, db: &State<Box<dyn LNVpsDb>>, vm_state: &State<VmStateCache>) -> ApiResult<Vec<ApiVmStatus>> { async fn v1_list_vms(
auth: Nip98Auth,
db: &State<Box<dyn LNVpsDb>>,
vm_state: &State<VmStateCache>,
) -> ApiResult<Vec<ApiVmStatus>> {
let pubkey = auth.event.pubkey.to_bytes(); let pubkey = auth.event.pubkey.to_bytes();
let uid = db.upsert_user(&pubkey).await?; let uid = db.upsert_user(&pubkey).await?;
let mut vms = db.list_user_vms(uid).await?; let mut vms = db.list_user_vms(uid).await?;
@ -81,17 +85,19 @@ async fn v1_list_vms(auth: Nip98Auth, db: &State<Box<dyn LNVpsDb>>, vm_state: &S
} }
let state = vm_state.get_state(vm.id).await; let state = vm_state.get_state(vm.id).await;
ret.push(ApiVmStatus { ret.push(ApiVmStatus { vm, status: state });
vm,
status: state,
});
} }
ApiData::ok(ret) ApiData::ok(ret)
} }
#[get("/api/v1/vm/<id>")] #[get("/api/v1/vm/<id>")]
async fn v1_get_vm(auth: Nip98Auth, db: &State<Box<dyn LNVpsDb>>, vm_state: &State<VmStateCache>, id: u64) -> ApiResult<ApiVmStatus> { async fn v1_get_vm(
auth: Nip98Auth,
db: &State<Box<dyn LNVpsDb>>,
vm_state: &State<VmStateCache>,
id: u64,
) -> ApiResult<ApiVmStatus> {
let pubkey = auth.event.pubkey.to_bytes(); let pubkey = auth.event.pubkey.to_bytes();
let uid = db.upsert_user(&pubkey).await?; let uid = db.upsert_user(&pubkey).await?;
let mut vm = db.get_vm(id).await?; let mut vm = db.get_vm(id).await?;
@ -103,10 +109,7 @@ async fn v1_get_vm(auth: Nip98Auth, db: &State<Box<dyn LNVpsDb>>, vm_state: &Sta
t.hydrate_up(db).await?; t.hydrate_up(db).await?;
} }
let state = vm_state.get_state(vm.id).await; let state = vm_state.get_state(vm.id).await;
ApiData::ok(ApiVmStatus { ApiData::ok(ApiVmStatus { vm, status: state })
vm,
status: state,
})
} }
#[get("/api/v1/image")] #[get("/api/v1/image")]

View File

@ -18,6 +18,7 @@ use std::time::Duration;
pub struct Settings { pub struct Settings {
pub db: String, pub db: String,
pub lnd: LndConfig, pub lnd: LndConfig,
pub read_only: bool,
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
@ -49,7 +50,7 @@ async fn main() -> Result<(), Error> {
} }
let status = VmStateCache::new(); let status = VmStateCache::new();
let mut worker = Worker::new(db.clone(), lnd.clone(), status.clone()); let mut worker = Worker::new(config.read_only, db.clone(), lnd.clone(), status.clone());
let sender = worker.sender(); let sender = worker.sender();
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {

View File

@ -4,5 +4,5 @@ pub mod host;
pub mod invoice; pub mod invoice;
pub mod nip98; pub mod nip98;
pub mod provisioner; pub mod provisioner;
pub mod worker;
pub mod status; pub mod status;
pub mod worker;

View File

@ -49,4 +49,4 @@ impl VmStateCache {
let guard = self.state.read().await; let guard = self.state.read().await;
guard.get(&id).cloned().unwrap_or_default() guard.get(&id).cloned().unwrap_or_default()
} }
} }

View File

@ -19,6 +19,7 @@ pub enum WorkJob {
} }
pub struct Worker { pub struct Worker {
read_only: bool,
db: Box<dyn LNVpsDb>, db: Box<dyn LNVpsDb>,
lnd: Client, lnd: Client,
provisioner: Box<dyn Provisioner>, provisioner: Box<dyn Provisioner>,
@ -28,10 +29,16 @@ pub struct Worker {
} }
impl Worker { impl Worker {
pub fn new<D: LNVpsDb + Clone + 'static>(db: D, lnd: Client, vm_state_cache: VmStateCache) -> Self { pub fn new<D: LNVpsDb + Clone + 'static>(
read_only: bool,
db: D,
lnd: Client,
vm_state_cache: VmStateCache,
) -> Self {
let (tx, rx) = unbounded_channel(); let (tx, rx) = unbounded_channel();
let p = LNVpsProvisioner::new(db.clone(), lnd.clone()); let p = LNVpsProvisioner::new(db.clone(), lnd.clone());
Self { Self {
read_only,
db: Box::new(db), db: Box::new(db),
provisioner: Box::new(p), provisioner: Box::new(p),
vm_state_cache, vm_state_cache,
@ -47,6 +54,9 @@ impl Worker {
/// Spawn a VM on the host /// Spawn a VM on the host
async fn spawn_vm(&self, vm: &Vm, vm_host: &VmHost, client: &ProxmoxClient) -> Result<()> { async fn spawn_vm(&self, vm: &Vm, vm_host: &VmHost, client: &ProxmoxClient) -> Result<()> {
if self.read_only {
bail!("Cant spawn VM's in read-only mode");
}
let mut ips = self.db.get_vm_ip_assignments(vm.id).await?; let mut ips = self.db.get_vm_ip_assignments(vm.id).await?;
if ips.is_empty() { if ips.is_empty() {
ips = self.provisioner.allocate_ips(vm.id).await?; ips = self.provisioner.allocate_ips(vm.id).await?;
@ -113,7 +123,7 @@ impl Worker {
let state = VmState { let state = VmState {
state: match s.status { state: match s.status {
VmStatus::Stopped => VmRunningState::Stopped, VmStatus::Stopped => VmRunningState::Stopped,
VmStatus::Running => VmRunningState::Running VmStatus::Running => VmRunningState::Running,
}, },
cpu_usage: s.cpu.unwrap_or(0.0), cpu_usage: s.cpu.unwrap_or(0.0),
mem_usage: s.mem.unwrap_or(0) as f32 / s.max_mem.unwrap_or(1) as f32, mem_usage: s.mem.unwrap_or(0) as f32 / s.max_mem.unwrap_or(1) as f32,
@ -138,7 +148,7 @@ impl Worker {
match job { match job {
WorkJob::CheckVm { vm_id } => { WorkJob::CheckVm { vm_id } => {
if let Err(e) = self.check_vm(vm_id).await { if let Err(e) = self.check_vm(vm_id).await {
error!("Failed to check VM {}: {:?}", vm_id, e); error!("Failed to check VM {}: {}", vm_id, e);
} }
} }
WorkJob::SendNotification { .. } => {} WorkJob::SendNotification { .. } => {}