api progress
This commit is contained in:
@ -6,7 +6,7 @@ create table users
|
||||
email varchar(200),
|
||||
contact_nip4 bit(1) not null,
|
||||
contact_nip17 bit(1) not null,
|
||||
contact_email bit(1) not null,
|
||||
contact_email bit(1) not null
|
||||
);
|
||||
create unique index ix_user_pubkey on users (pubkey);
|
||||
create unique index ix_user_email on users (email);
|
||||
@ -55,14 +55,14 @@ create table vm_host_disk
|
||||
create table vm_os_image
|
||||
(
|
||||
id integer unsigned not null auto_increment primary key,
|
||||
name varchar(200) not null,
|
||||
distribution smallint unsigned not null,
|
||||
flavour varchar(50) not null,
|
||||
version varchar(50) not null,
|
||||
enabled bit(1) not null,
|
||||
url varchar(1024) not null,
|
||||
release_date timestamp not null,
|
||||
url varchar(1024) not null
|
||||
);
|
||||
create unique index ix_vm_os_image_name on vm_os_image (name);
|
||||
create unique index ix_vm_os_image on vm_os_image (distribution, flavour, version);
|
||||
create table ip_range
|
||||
(
|
||||
id integer unsigned not null auto_increment primary key,
|
||||
@ -72,6 +72,7 @@ create table ip_range
|
||||
|
||||
constraint fk_ip_range_region foreign key (region_id) references vm_host_region (id)
|
||||
);
|
||||
create unique index ix_ip_range_cidr on ip_range (cidr);
|
||||
create table vm_cost_plan
|
||||
(
|
||||
id integer unsigned not null auto_increment primary key,
|
||||
|
48
lnvps_db/src/hydrate.rs
Normal file
48
lnvps_db/src/hydrate.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::{LNVpsDb, Vm, VmTemplate};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Hydrate {
|
||||
/// Load parent resources
|
||||
async fn hydrate_up(&mut self, db: &Box<dyn LNVpsDb>) -> Result<()>;
|
||||
|
||||
/// Load child resources
|
||||
async fn hydrate_down(&mut self, db: &Box<dyn LNVpsDb>) -> Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Hydrate for Vm {
|
||||
async fn hydrate_up(&mut self, db: &Box<dyn LNVpsDb>) -> Result<()> {
|
||||
let image = db.get_os_image(self.image_id).await?;
|
||||
let template = db.get_vm_template(self.template_id).await?;
|
||||
let ssh_key = db.get_user_ssh_key(self.ssh_key_id).await?;
|
||||
|
||||
self.image = Some(image);
|
||||
self.template = Some(template);
|
||||
self.ssh_key = Some(ssh_key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn hydrate_down(&mut self, db: &Box<dyn LNVpsDb>) -> Result<()> {
|
||||
let payments = db.list_vm_payment(self.id).await?;
|
||||
|
||||
self.payments = Some(payments);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Hydrate for VmTemplate {
|
||||
async fn hydrate_up(&mut self, db: &Box<dyn LNVpsDb>) -> Result<()> {
|
||||
let cost_plan = db.get_cost_plan(self.cost_plan_id).await?;
|
||||
let region = db.get_host_region(self.region_id).await?;
|
||||
self.cost_plan = Some(cost_plan);
|
||||
self.region = Some(region);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn hydrate_down(&mut self, db: &Box<dyn LNVpsDb>) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ use async_trait::async_trait;
|
||||
mod model;
|
||||
#[cfg(feature = "mysql")]
|
||||
mod mysql;
|
||||
pub mod hydrate;
|
||||
|
||||
pub use model::*;
|
||||
#[cfg(feature = "mysql")]
|
||||
@ -27,7 +28,7 @@ pub trait LNVpsDb: Sync + Send {
|
||||
async fn delete_user(&self, id: u64) -> Result<()>;
|
||||
|
||||
/// Insert a new user ssh key
|
||||
async fn insert_user_ssh_key(&self, new_key: UserSshKey) -> Result<u64>;
|
||||
async fn insert_user_ssh_key(&self, new_key: &UserSshKey) -> Result<u64>;
|
||||
|
||||
/// Get user ssh key by id
|
||||
async fn get_user_ssh_key(&self, id: u64) -> Result<UserSshKey>;
|
||||
@ -45,11 +46,14 @@ pub trait LNVpsDb: Sync + Send {
|
||||
async fn list_hosts(&self) -> Result<Vec<VmHost>>;
|
||||
|
||||
/// Update host resources (usually from [auto_discover])
|
||||
async fn update_host(&self, host: VmHost) -> Result<()>;
|
||||
async fn update_host(&self, host: &VmHost) -> Result<()>;
|
||||
|
||||
/// List VM's owned by a specific user
|
||||
async fn list_host_disks(&self, host_id: u64) -> Result<Vec<VmHostDisk>>;
|
||||
|
||||
/// Get OS image by id
|
||||
async fn get_os_image(&self, id: u64) -> Result<VmOsImage>;
|
||||
|
||||
/// List available OS images
|
||||
async fn list_os_image(&self) -> Result<Vec<VmOsImage>>;
|
||||
|
||||
@ -59,14 +63,20 @@ pub trait LNVpsDb: Sync + Send {
|
||||
/// Get a VM cost plan by id
|
||||
async fn get_cost_plan(&self, id: u64) -> Result<VmCostPlan>;
|
||||
|
||||
/// Get VM template by id
|
||||
async fn get_vm_template(&self, id: u64) -> Result<VmTemplate>;
|
||||
|
||||
/// List VM templates
|
||||
async fn list_vm_templates(&self) -> Result<Vec<VmTemplate>>;
|
||||
|
||||
/// List VM's owned by a specific user
|
||||
async fn list_user_vms(&self, id: u64) -> Result<Vec<Vm>>;
|
||||
|
||||
/// Get a VM by id
|
||||
async fn get_vm(&self, vm_id: u64) -> Result<Vm>;
|
||||
|
||||
/// Insert a new VM record
|
||||
async fn insert_vm(&self, vm: Vm) -> Result<u64>;
|
||||
async fn insert_vm(&self, vm: &Vm) -> Result<u64>;
|
||||
|
||||
/// List VM ip assignments
|
||||
async fn get_vm_ip_assignments(&self, vm_id: u64) -> Result<Vec<VmIpAssignment>>;
|
||||
@ -75,8 +85,8 @@ pub trait LNVpsDb: Sync + Send {
|
||||
async fn list_vm_payment(&self, vm_id: u64) -> Result<Vec<VmPayment>>;
|
||||
|
||||
/// Insert a new VM payment record
|
||||
async fn insert_vm_payment(&self, vm_payment: VmPayment) -> Result<u64>;
|
||||
async fn insert_vm_payment(&self, vm_payment: &VmPayment) -> Result<u64>;
|
||||
|
||||
/// Update a VM payment record
|
||||
async fn update_vm_payment(&self, vm_payment: VmPayment) -> Result<()>;
|
||||
async fn update_vm_payment(&self, vm_payment: &VmPayment) -> Result<()>;
|
||||
}
|
@ -18,12 +18,13 @@ pub struct User {
|
||||
pub contact_email: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug)]
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug, Default)]
|
||||
pub struct UserSshKey {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub user_id: u64,
|
||||
pub created: DateTime<Utc>,
|
||||
#[serde(skip_serializing)]
|
||||
pub key_data: String,
|
||||
|
||||
#[sqlx(skip)]
|
||||
@ -79,24 +80,29 @@ pub struct VmHostDisk {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[repr(u16)]
|
||||
pub enum DiskType {
|
||||
#[default]
|
||||
HDD = 0,
|
||||
SSD = 1,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[repr(u16)]
|
||||
pub enum DiskInterface {
|
||||
#[default]
|
||||
SATA = 0,
|
||||
SCSI = 1,
|
||||
PCIe = 2,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type, Default)]
|
||||
#[repr(u16)]
|
||||
pub enum OsDistribution {
|
||||
#[default]
|
||||
Ubuntu = 0,
|
||||
Debian = 1,
|
||||
}
|
||||
@ -106,11 +112,12 @@ pub enum OsDistribution {
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug)]
|
||||
pub struct VmOsImage {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub distribution: OsDistribution,
|
||||
pub flavour: String,
|
||||
pub version: String,
|
||||
pub enabled: bool,
|
||||
pub release_date: DateTime<Utc>,
|
||||
#[serde(skip_serializing)]
|
||||
/// URL location of cloud image
|
||||
pub url: String,
|
||||
}
|
||||
@ -124,6 +131,7 @@ pub struct IpRange {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[repr(u16)]
|
||||
pub enum VmCostPlanIntervalType {
|
||||
Day = 0,
|
||||
@ -144,7 +152,7 @@ pub struct VmCostPlan {
|
||||
|
||||
/// Offers.
|
||||
/// These are the same as the offers visible to customers
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug)]
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug, Default)]
|
||||
pub struct VmTemplate {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
@ -154,6 +162,7 @@ pub struct VmTemplate {
|
||||
pub expires: Option<DateTime<Utc>>,
|
||||
pub cpu: u16,
|
||||
pub memory: u64,
|
||||
pub disk_size: u64,
|
||||
pub disk_type: DiskType,
|
||||
pub disk_interface: DiskInterface,
|
||||
pub cost_plan_id: u64,
|
||||
@ -167,7 +176,7 @@ pub struct VmTemplate {
|
||||
pub region: Option<VmHostRegion>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug)]
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug, Default)]
|
||||
pub struct Vm {
|
||||
/// Unique VM ID (Same in proxmox)
|
||||
pub id: u64,
|
||||
@ -193,6 +202,19 @@ pub struct Vm {
|
||||
pub disk_size: u64,
|
||||
/// The [VmHostDisk] this VM is on
|
||||
pub disk_id: u64,
|
||||
|
||||
#[sqlx(skip)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image: Option<VmOsImage>,
|
||||
#[sqlx(skip)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub template: Option<VmTemplate>,
|
||||
#[sqlx(skip)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ssh_key: Option<UserSshKey>,
|
||||
#[sqlx(skip)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub payments: Option<Vec<VmPayment>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, FromRow, Clone, Debug)]
|
||||
|
@ -25,11 +25,11 @@ impl LNVpsDbMysql {
|
||||
|
||||
#[async_trait]
|
||||
impl LNVpsDb for LNVpsDbMysql {
|
||||
async fn migrate(&self) -> anyhow::Result<()> {
|
||||
async fn migrate(&self) -> Result<()> {
|
||||
sqlx::migrate!().run(&self.db).await.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn upsert_user(&self, pubkey: &[u8; 32]) -> anyhow::Result<u64> {
|
||||
async fn upsert_user(&self, pubkey: &[u8; 32]) -> Result<u64> {
|
||||
let res = sqlx::query("insert ignore into users(pubkey) values(?) returning id")
|
||||
.bind(pubkey.as_slice())
|
||||
.fetch_optional(&self.db)
|
||||
@ -46,7 +46,11 @@ impl LNVpsDb for LNVpsDbMysql {
|
||||
}
|
||||
|
||||
async fn get_user(&self, id: u64) -> Result<User> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from users where id=?")
|
||||
.bind(id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn update_user(&self, user: &User) -> Result<()> {
|
||||
@ -57,12 +61,23 @@ impl LNVpsDb for LNVpsDbMysql {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn insert_user_ssh_key(&self, new_key: UserSshKey) -> Result<u64> {
|
||||
todo!()
|
||||
async fn insert_user_ssh_key(&self, new_key: &UserSshKey) -> Result<u64> {
|
||||
Ok(sqlx::query("insert into user_ssh_key(name,user_id,key_data) values(?, ?, ?) returning id")
|
||||
.bind(&new_key.name)
|
||||
.bind(&new_key.user_id)
|
||||
.bind(&new_key.key_data)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)?
|
||||
.try_get(0)?)
|
||||
}
|
||||
|
||||
async fn get_user_ssh_key(&self, id: u64) -> Result<UserSshKey> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from user_ssh_key where id=?")
|
||||
.bind(id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn delete_user_ssh_key(&self, id: u64) -> Result<()> {
|
||||
@ -70,21 +85,29 @@ impl LNVpsDb for LNVpsDbMysql {
|
||||
}
|
||||
|
||||
async fn list_user_ssh_key(&self, user_id: u64) -> Result<Vec<UserSshKey>> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from user_ssh_key where user_id = ?")
|
||||
.bind(user_id)
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn get_host_region(&self, id: u64) -> Result<VmHostRegion> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from vm_host_region where id=?")
|
||||
.bind(id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn list_hosts(&self) -> anyhow::Result<Vec<VmHost>> {
|
||||
async fn list_hosts(&self) -> Result<Vec<VmHost>> {
|
||||
sqlx::query_as("select * from vm_host")
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn update_host(&self, host: VmHost) -> anyhow::Result<()> {
|
||||
async fn update_host(&self, host: &VmHost) -> Result<()> {
|
||||
sqlx::query("update vm_host set name = ?, cpu = ?, memory = ? where id = ?")
|
||||
.bind(&host.name)
|
||||
.bind(&host.cpu)
|
||||
@ -95,7 +118,7 @@ impl LNVpsDb for LNVpsDbMysql {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_host_disks(&self, host_id: u64) -> anyhow::Result<Vec<VmHostDisk>> {
|
||||
async fn list_host_disks(&self, host_id: u64) -> Result<Vec<VmHostDisk>> {
|
||||
sqlx::query_as("select * from vm_host_disk where host_id = ?")
|
||||
.bind(&host_id)
|
||||
.fetch_all(&self.db)
|
||||
@ -103,20 +126,46 @@ impl LNVpsDb for LNVpsDbMysql {
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn get_os_image(&self, id: u64) -> Result<VmOsImage> {
|
||||
sqlx::query_as("select * from vm_os_image where id=?")
|
||||
.bind(id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn list_os_image(&self) -> Result<Vec<VmOsImage>> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from vm_os_image")
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn list_ip_range(&self) -> Result<Vec<IpRange>> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from ip_range")
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn get_cost_plan(&self, id: u64) -> Result<VmCostPlan> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from vm_cost_plan where id=?")
|
||||
.bind(id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn list_vm_templates(&self) -> anyhow::Result<Vec<VmTemplate>> {
|
||||
sqlx::query_as("select * from vm_template where enabled = 1 and (expires is null or expires > now())")
|
||||
async fn get_vm_template(&self, id: u64) -> Result<VmTemplate> {
|
||||
sqlx::query_as("select * from vm_template where id=?")
|
||||
.bind(id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn list_vm_templates(&self) -> Result<Vec<VmTemplate>> {
|
||||
sqlx::query_as("select * from vm_template")
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
@ -130,23 +179,71 @@ impl LNVpsDb for LNVpsDbMysql {
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn insert_vm(&self, vm: Vm) -> Result<u64> {
|
||||
todo!()
|
||||
async fn get_vm(&self, vm_id: u64) -> Result<Vm> {
|
||||
sqlx::query_as("select * from vm where id = ?")
|
||||
.bind(&vm_id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn insert_vm(&self, vm: &Vm) -> Result<u64> {
|
||||
Ok(sqlx::query("insert into vm(host_id,user_id,image_id,template_id,ssh_key_id,created,expires,cpu,memory,disk_size,disk_id) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) returning id")
|
||||
.bind(&vm.host_id)
|
||||
.bind(&vm.user_id)
|
||||
.bind(&vm.image_id)
|
||||
.bind(&vm.template_id)
|
||||
.bind(&vm.ssh_key_id)
|
||||
.bind(&vm.created)
|
||||
.bind(&vm.expires)
|
||||
.bind(&vm.cpu)
|
||||
.bind(&vm.memory)
|
||||
.bind(&vm.disk_size)
|
||||
.bind(&vm.disk_id)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)?
|
||||
.try_get(0)?)
|
||||
}
|
||||
|
||||
async fn get_vm_ip_assignments(&self, vm_id: u64) -> Result<Vec<VmIpAssignment>> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from vm_ip_assignment where vm_id=?")
|
||||
.bind(vm_id)
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn list_vm_payment(&self, vm_id: u64) -> Result<Vec<VmPayment>> {
|
||||
todo!()
|
||||
sqlx::query_as("select * from vm_payment where vm_id=?")
|
||||
.bind(vm_id)
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
async fn insert_vm_payment(&self, vm_payment: VmPayment) -> Result<u64> {
|
||||
todo!()
|
||||
async fn insert_vm_payment(&self, vm_payment: &VmPayment) -> Result<u64> {
|
||||
Ok(sqlx::query("insert into vm_payment(vm_id,created,expires,amount,invoice,time_value,is_paid) values(?,?,?,?,?,?,?) returning id")
|
||||
.bind(&vm_payment.vm_id)
|
||||
.bind(&vm_payment.created)
|
||||
.bind(&vm_payment.expires)
|
||||
.bind(&vm_payment.amount)
|
||||
.bind(&vm_payment.invoice)
|
||||
.bind(&vm_payment.time_value)
|
||||
.bind(&vm_payment.is_paid)
|
||||
.fetch_one(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)?
|
||||
.try_get(0)?)
|
||||
}
|
||||
|
||||
async fn update_vm_payment(&self, vm_payment: VmPayment) -> Result<()> {
|
||||
todo!()
|
||||
async fn update_vm_payment(&self, vm_payment: &VmPayment) -> Result<()> {
|
||||
sqlx::query("update vm_payment set is_paid = ? where id = ?")
|
||||
.bind(&vm_payment.is_paid)
|
||||
.bind(&vm_payment.id)
|
||||
.execute(&self.db)
|
||||
.await
|
||||
.map_err(Error::new)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user