From e67e742209b0bcade7d5d2ab39ce902d4d61de45 Mon Sep 17 00:00:00 2001 From: EmirVildanov <reddog201030@gmail.com> Date: Fri, 31 May 2024 10:28:24 +0300 Subject: [PATCH] fix: cover local SQL querying with admin privileges to allow VTables interaction --- sbroad-core/src/backend/sql/ir.rs | 1 + sbroad-core/src/backend/sql/space.rs | 58 ++++++++++++------- .../engine/helpers/storage/runtime.rs | 26 +++++++-- .../src/executor/engine/helpers/vshard.rs | 36 +++++++----- 4 files changed, 81 insertions(+), 40 deletions(-) diff --git a/sbroad-core/src/backend/sql/ir.rs b/sbroad-core/src/backend/sql/ir.rs index fa28cf3ecf..c74aaf2c2d 100644 --- a/sbroad-core/src/backend/sql/ir.rs +++ b/sbroad-core/src/backend/sql/ir.rs @@ -488,6 +488,7 @@ impl ExecutionPlan { // BETWEEN can refer to the same virtual table multiple times. if tmp_spaces.get(&name).is_none() { let space = TmpSpace::initialize( + &name, self, name_base, *motion_id, diff --git a/sbroad-core/src/backend/sql/space.rs b/sbroad-core/src/backend/sql/space.rs index 62210140e4..4d6cfb32fd 100644 --- a/sbroad-core/src/backend/sql/space.rs +++ b/sbroad-core/src/backend/sql/space.rs @@ -9,6 +9,7 @@ mod prod_imports { pub use crate::errors::{Action, Entity}; pub use crate::ir::value::{EncodedValue, Value}; pub use tarantool::index::{FieldType, IndexOptions, IndexType, Part}; + pub use tarantool::session::with_su; pub use tarantool::space::{Field, Space, SpaceCreateOptions, SpaceType}; pub use tarantool::tuple::Tuple; } @@ -23,6 +24,8 @@ pub struct TmpSpace { pub name: SmolStr, } +pub const ADMIN_ID: u32 = 1; + impl TmpSpace { /// Create a temporary space. /// @@ -31,13 +34,13 @@ impl TmpSpace { #[allow(unused_variables)] #[allow(clippy::too_many_lines)] pub fn initialize( + table_name: &SmolStr, exec_plan: &ExecutionPlan, base: &str, motion_id: usize, buckets: &Buckets, engine: &SpaceEngine, ) -> Result<TmpSpace, SbroadError> { - let name = TmpSpace::generate_space_name(base, motion_id); #[cfg(not(feature = "mock"))] { let vtable = exec_plan.get_motion_vtable(motion_id)?; @@ -71,30 +74,36 @@ impl TmpSpace { ..Default::default() }; - let space = Space::create(&name, &options).map_err(|e| { - SbroadError::FailedTo( - Action::Create, - Some(Entity::Space), - format_smolstr!("{name}: {e}"), - ) - })?; - let cleanup = |space: Space| match space.drop() { - Ok(_) => {} - Err(e) => { - error!( - Option::from("Temporary space"), - &format!("Failed to drop {}: {e}", name) - ); + let space = with_su(ADMIN_ID, || -> Result<Space, SbroadError> { + Space::create(table_name, &options).map_err(|e| { + SbroadError::FailedTo( + Action::Create, + Some(Entity::Space), + format_smolstr!("{table_name}: {e}"), + ) + }) + })??; + let cleanup = |space: Space| { + let drop_space_res = with_su(ADMIN_ID, || space.drop()); + match drop_space_res { + Ok(_) => {} + Err(e) => { + error!( + Option::from("Temporary space"), + &format!("Failed to drop {}: {e}", table_name) + ); + } } }; - match space.create_index(&pk_name, &pk) { + let create_index_res = with_su(ADMIN_ID, || space.create_index(&pk_name, &pk))?; + match create_index_res { Ok(_) => {} Err(e) => { cleanup(space); return Err(SbroadError::FailedTo( Action::Create, Some(Entity::Index), - format_smolstr!("{pk_name} for space {name}: {e}"), + format_smolstr!("{pk_name} for space {table_name}: {e}"), )); } } @@ -116,20 +125,23 @@ impl TmpSpace { )); } }; - match space.insert(&tuple) { + let tuple_insert_res = with_su(ADMIN_ID, || space.insert(&tuple))?; + match tuple_insert_res { Ok(_) => {} Err(e) => { cleanup(space); return Err(SbroadError::FailedTo( Action::Insert, Some(Entity::Tuple), - format_smolstr!("tuple {tuple:?} into {name}: {e}"), + format_smolstr!("tuple {tuple:?} into {table_name}: {e}"), )); } } } } - Ok(TmpSpace { name }) + Ok(TmpSpace { + name: table_name.clone(), + }) } #[must_use] @@ -147,8 +159,10 @@ impl Drop for TmpSpace { fn drop(&mut self) { #[cfg(not(feature = "mock"))] { - if let Some(space) = Space::find(&self.name) { - if let Err(e) = space.drop() { + let space_find_res = with_su(ADMIN_ID, || Space::find(&self.name)); + if let Ok(Some(space)) = space_find_res { + let space_drop_res = with_su(ADMIN_ID, || space.drop()); + if let Err(e) = space_drop_res { error!( Option::from("Temporary space"), &format!("Failed to drop {} space: {e}", self.name) diff --git a/sbroad-core/src/executor/engine/helpers/storage/runtime.rs b/sbroad-core/src/executor/engine/helpers/storage/runtime.rs index b4bf656e52..2a87af0632 100644 --- a/sbroad-core/src/executor/engine/helpers/storage/runtime.rs +++ b/sbroad-core/src/executor/engine/helpers/storage/runtime.rs @@ -2,8 +2,10 @@ use std::any::Any; use sbroad_proc::otm_child_span; use smol_str::{format_smolstr, ToSmolStr}; +use tarantool::session::with_su; use tarantool::{tlua::LuaFunction, tuple::Tuple}; +use crate::backend::sql::space::ADMIN_ID; use crate::ir::ExecuteOptions; use crate::{error, errors::SbroadError, ir::value::Value, otm::child_span}; @@ -63,7 +65,11 @@ pub fn read_prepared( .get("read") .ok_or_else(|| SbroadError::LuaError("Lua function `read` not found".into()))?; - match exec_sql.call_with_args::<Tuple, _>((stmt_id, stmt, params, max_rows, options)) { + // `with_su` is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((stmt_id, stmt, params, max_rows, options)) + })?; + match call_res { Ok(v) => Ok(Box::new(v) as Box<dyn Any>), Err(e) => { error!(Option::from("read_prepared"), &format!("{e:?}")); @@ -85,7 +91,11 @@ pub fn read_unprepared( .get("read") .ok_or_else(|| SbroadError::LuaError("Lua function `read` not found".into()))?; - match exec_sql.call_with_args::<Tuple, _>((0, stmt, params, max_rows, options)) { + // `with_su` is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((0, stmt, params, max_rows, options)) + })?; + match call_res { Ok(v) => Ok(Box::new(v) as Box<dyn Any>), Err(e) => { error!(Option::from("read_unprepared"), &format!("{e:?}")); @@ -107,7 +117,11 @@ pub fn write_prepared( .get("write") .ok_or_else(|| SbroadError::LuaError("Lua function `write` not found".into()))?; - match exec_sql.call_with_args::<Tuple, _>((stmt_id, stmt, params, options)) { + // `with_su` is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((stmt_id, stmt, params, options)) + })?; + match call_res { Ok(v) => Ok(Box::new(v) as Box<dyn Any>), Err(e) => { error!(Option::from("write_prepared"), &format!("{e:?}")); @@ -128,7 +142,11 @@ pub fn write_unprepared( .get("write") .ok_or_else(|| SbroadError::LuaError("Lua function `write` not found".into()))?; - match exec_sql.call_with_args::<Tuple, _>((0, stmt, params, options)) { + // `with_su` is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((0, stmt, params, options)) + })?; + match call_res { Ok(v) => Ok(Box::new(v) as Box<dyn Any>), Err(e) => { error!(Option::from("write_unprepared"), &format!("{e:?}")); diff --git a/sbroad-core/src/executor/engine/helpers/vshard.rs b/sbroad-core/src/executor/engine/helpers/vshard.rs index 8446dc79a7..1a5f976640 100644 --- a/sbroad-core/src/executor/engine/helpers/vshard.rs +++ b/sbroad-core/src/executor/engine/helpers/vshard.rs @@ -21,8 +21,10 @@ use crate::{ use rand::{thread_rng, Rng}; use sbroad_proc::otm_child_span; use smol_str::format_smolstr; +use tarantool::session::with_su; use tarantool::{tlua::LuaFunction, tuple::Tuple}; +use crate::backend::sql::space::ADMIN_ID; use crate::{ debug, error, errors::{Entity, SbroadError}, @@ -57,12 +59,11 @@ fn dql_on_some( .ok_or_else(|| SbroadError::LuaError("Lua function `dql_on_some` not found".into()))?; let waiting_timeout = metadata.waiting_timeout(); - match exec_sql.call_with_args::<Tuple, _>(( - rs_ir, - is_readonly, - waiting_timeout, - vtable_max_rows, - )) { + // `with_su` is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((rs_ir, is_readonly, waiting_timeout, vtable_max_rows)) + })?; + match call_res { Ok(v) => { debug!(Option::from("dql_on_some"), &format!("Result: {:?}", &v)); Ok(Box::new(v)) @@ -92,7 +93,11 @@ fn dml_on_some( .ok_or_else(|| SbroadError::LuaError("Lua function `dml_on_some` not found".into()))?; let waiting_timeout = metadata.waiting_timeout(); - match exec_sql.call_with_args::<Tuple, _>((rs_ir, is_readonly, waiting_timeout)) { + // `with_su` is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((rs_ir, is_readonly, waiting_timeout)) + })?; + match call_res { Ok(v) => Ok(Box::new(v)), Err(e) => { error!(Option::from("dml_on_some"), &format!("{e:?}")); @@ -118,12 +123,11 @@ fn dql_on_all( .ok_or_else(|| SbroadError::LuaError("Lua function `dql_on_all` not found".into()))?; let waiting_timeout = metadata.waiting_timeout(); - match exec_sql.call_with_args::<Tuple, _>(( - required, - optional, - waiting_timeout, - vtable_max_rows, - )) { + // `with_su` coverage is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((required, optional, waiting_timeout, vtable_max_rows)) + })?; + match call_res { Ok(v) => { debug!(Option::from("dql_on_all"), &format!("Result: {:?}", &v)); Ok(Box::new(v)) @@ -153,7 +157,11 @@ fn dml_on_all( .ok_or_else(|| SbroadError::LuaError("Lua function `dml_on_all` not found".into()))?; let waiting_timeout = metadata.waiting_timeout(); - match exec_sql.call_with_args::<Tuple, _>((required, optional, is_readonly, waiting_timeout)) { + // `with_su` coverage is used to read from virtual tables previously created by admin. + let call_res = with_su(ADMIN_ID, || { + exec_sql.call_with_args::<Tuple, _>((required, optional, is_readonly, waiting_timeout)) + })?; + match call_res { Ok(v) => Ok(Box::new(v)), Err(e) => { error!(Option::from("dml_on_all"), &format!("{e:?}")); -- GitLab