improve query handling in new_vm

enhanced transaction error handling
bind all string input into NewVmReq submission query
This commit is contained in:
Noor 2025-05-28 17:17:26 +05:30
parent 5ccd432566
commit 05759a5149
Signed by: noormohammedb
GPG Key ID: D83EFB8B3B967146

@ -202,52 +202,67 @@ impl NewVmReq {
pub async fn submit(self, db: &Surreal<Client>) -> Result<(), Error> {
let locked_nano = self.locked_nano;
let account = self.admin.key().to_string();
let vm_id = self.id.key().to_string();
let vm_node = self.vm_node.key().to_string();
// TODO: check for possible injection and maybe use .bind()
let query = format!(
"
let tx_query = format!("
BEGIN TRANSACTION;
UPDATE account:{account} SET balance -= {locked_nano};
IF account:{account}.balance < 0 {{
LET $account = $account_input;
LET $new_vm_req = $new_vm_req_input;
LET $vm_node = $vm_node_input;
LET $hostname = $hostname_input;
LET $dtrfs_url = $dtrfs_url_input;
LET $dtrfs_sha = $dtrfs_sha_input;
LET $kernel_url = $kernel_url_input;
LET $kernel_sha = $kernel_sha_input;
UPDATE $account SET balance -= {locked_nano};
IF $account.balance < 0 {{
THROW 'Insufficient funds.'
}};
UPDATE account:{account} SET tmp_locked += {locked_nano};
UPDATE $account SET tmp_locked += {locked_nano};
RELATE
account:{account}
->new_vm_req:{vm_id}
->vm_node:{vm_node}
$account
->$new_vm_req
->$vm_node
CONTENT {{
created_at: time::now(), hostname: '{}', vcpus: {}, memory_mb: {}, disk_size_gb: {},
extra_ports: {:?}, public_ipv4: {:?}, public_ipv6: {:?},
dtrfs_url: '{}', dtrfs_sha: '{}', kernel_url: '{}', kernel_sha: '{}',
created_at: time::now(), hostname: $hostname, vcpus: {}, memory_mb: {}, disk_size_gb: {},
extra_ports: {:?}, public_ipv4: {}, public_ipv6: {},
dtrfs_url: $dtrfs_url, dtrfs_sha: $dtrfs_sha, kernel_url: $kernel_url, kernel_sha: $kernel_sha,
price_per_unit: {}, locked_nano: {locked_nano}, error: ''
}};
COMMIT TRANSACTION;
",
self.hostname,
COMMIT TRANSACTION;",
self.vcpus,
self.memory_mb,
self.disk_size_gb,
self.extra_ports,
self.public_ipv4,
self.public_ipv6,
self.dtrfs_url,
self.dtrfs_sha,
self.kernel_url,
self.kernel_sha,
self.price_per_unit
);
//let _: Vec<Self> = db.insert(NEW_VM_REQ).relation(self).await?;
let mut query_resp = db.query(query).await?;
let resp_err = query_resp.take_errors();
let mut query_resp = db
.query(tx_query)
.bind(("account_input", self.admin))
.bind(("new_vm_req_input", self.id))
.bind(("vm_node_input", self.vm_node))
.bind(("hostname_input", self.hostname))
.bind(("dtrfs_url_input", self.dtrfs_url))
.bind(("dtrfs_sha_input", self.dtrfs_sha))
.bind(("kernel_url_input", self.kernel_url))
.bind(("kernel_sha_input", self.kernel_sha))
.await?;
if let Some(surrealdb::Error::Api(surrealdb::error::Api::Query(tx_query_error))) =
resp_err.get(&1)
{
log::error!("Transaction error: {tx_query_error}");
let query_err = query_resp.take_errors();
if !query_err.is_empty() {
let tx_fail_err_str =
String::from("The query was not executed due to a failed transaction");
if query_err.contains_key(&9) && query_err[&9].to_string() != tx_fail_err_str {
log::error!("Transaction error: {}", query_err[&9]);
return Err(Error::InsufficientFunds);
} else {
log::error!("Unknown error in submit_new_vm_req: {query_err:?}");
return Err(Error::Unknown("submit_new_vm_req".to_string()));
}
}
Ok(())