Skip to content

Commit

Permalink
refactor(rust): extract OCKAM_SQLITE_IN_MEMORY env var usage up to …
Browse files Browse the repository at this point in the history
…the cli state initialization
  • Loading branch information
adrianbenavides committed Dec 16, 2024
1 parent e25a484 commit 9389b26
Show file tree
Hide file tree
Showing 13 changed files with 125 additions and 90 deletions.
133 changes: 80 additions & 53 deletions implementations/rust/ockam/ockam_api/src/cli_state/cli_state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rand::random;
use std::borrow::Cow;
use std::path::{Path, PathBuf};
use tokio::sync::broadcast::{channel, Receiver, Sender};

Expand Down Expand Up @@ -40,7 +41,7 @@ const NOTIFICATIONS_CHANNEL_CAPACITY: usize = 16;
///
#[derive(Debug, Clone)]
pub struct CliState {
dir: PathBuf,
pub mode: CliStateMode<'static>,
database: SqlxDatabase,
application_database: SqlxDatabase,
exporting_enabled: ExportingEnabled,
Expand All @@ -51,12 +52,15 @@ pub struct CliState {

impl CliState {
/// Create a new CliState in a given directory
pub fn new(dir: &Path) -> Result<Self> {
Executor::execute_future(Self::create(dir.into()))?
pub fn new(mode: CliStateMode<'static>) -> Result<Self> {
Executor::execute_future(Self::create(mode))?
}

pub fn dir(&self) -> PathBuf {
self.dir.clone()
pub fn dir(&self) -> Result<PathBuf> {
match &self.mode {
CliStateMode::Persistent(dir) => Ok(dir.as_ref().to_path_buf()),
CliStateMode::InMemory => Self::default_dir(),
}
}

pub fn database(&self) -> SqlxDatabase {
Expand All @@ -68,7 +72,7 @@ impl CliState {
}

pub fn database_configuration(&self) -> Result<DatabaseConfiguration> {
Self::make_database_configuration(&self.dir)
Self::make_database_configuration(&self.mode)
}

pub fn is_using_in_memory_database(&self) -> Result<bool> {
Expand All @@ -91,7 +95,7 @@ impl CliState {
}

pub fn application_database_configuration(&self) -> Result<DatabaseConfiguration> {
Self::make_application_database_configuration(&self.dir)
Self::make_application_database_configuration(&self.mode)
}

pub fn subscribe_to_notifications(&self) -> Receiver<Notification> {
Expand Down Expand Up @@ -122,9 +126,16 @@ impl CliState {

/// These functions allow to create and reset the local state
impl CliState {
/// Return a new CliState using a default directory to store its data
pub fn with_default_dir() -> Result<Self> {
Self::new(Self::default_dir()?.as_path())
/// Return a new CliState using a default directory to store its data or
/// using an in-memory storage if the OCKAM_SQLITE_IN_MEMORY environment variable is set to true
pub fn from_env() -> Result<Self> {
let in_memory = get_env_with_default::<bool>(OCKAM_SQLITE_IN_MEMORY, false)?;
let mode = if in_memory {
CliStateMode::InMemory
} else {
CliStateMode::with_default_dir()?
};
Self::new(mode)
}

/// Stop nodes and remove all the directories storing state
Expand All @@ -150,13 +161,16 @@ impl CliState {

/// Delete the local data on disk: sqlite database file and log files
pub fn delete_local_data(&self) -> Result<()> {
Self::delete_at(&self.dir)
if let CliStateMode::Persistent(dir) = &self.mode {
Self::delete_at(dir)?;
}
Ok(())
}

/// Reset all directories and return a new CliState
pub async fn recreate(&self) -> Result<CliState> {
self.reset().await?;
Self::create(self.dir.clone()).await
Self::create(self.mode.clone()).await
}

/// Backup and reset is used to save aside
Expand All @@ -182,10 +196,9 @@ impl CliState {

// Reset state
Self::delete_at(&dir)?;
let state = Self::new(&dir)?;
Self::new(CliStateMode::Persistent(Cow::Owned(dir.clone())))?;

let dir = &state.dir;
let backup_dir = CliState::backup_default_dir().unwrap();
let backup_dir = CliState::backup_default_dir()?;
eprintln!("The {dir:?} directory has been reset and has been backed up to {backup_dir:?}");
Ok(())
}
Expand All @@ -210,10 +223,12 @@ impl CliState {
/// Low-level functions for creating / deleting CliState files
impl CliState {
/// Create a new CliState where the data is stored at a given path
pub async fn create(dir: PathBuf) -> Result<Self> {
std::fs::create_dir_all(&dir)?;
let database = SqlxDatabase::create(&Self::make_database_configuration(&dir)?).await?;
let configuration = Self::make_application_database_configuration(&dir)?;
pub async fn create(mode: CliStateMode<'static>) -> Result<Self> {
if let CliStateMode::Persistent(ref dir) = mode {
std::fs::create_dir_all(dir.as_path())?;
}
let database = SqlxDatabase::create(&Self::make_database_configuration(&mode)?).await?;
let configuration = Self::make_application_database_configuration(&mode)?;
let application_database =
SqlxDatabase::create_application_database(&configuration).await?;
debug!("Opened the main database with options {:?}", database);
Expand All @@ -223,7 +238,7 @@ impl CliState {
);
let (notifications, _) = channel::<Notification>(NOTIFICATIONS_CHANNEL_CAPACITY);
let state = Self {
dir,
mode,
database,
application_database,
// We initialize the CliState with no tracing.
Expand Down Expand Up @@ -252,63 +267,65 @@ impl CliState {
}

/// If the postgres database is configured, return the postgres configuration
pub(super) fn make_database_configuration(root_path: &Path) -> Result<DatabaseConfiguration> {
pub(super) fn make_database_configuration(
mode: &CliStateMode,
) -> Result<DatabaseConfiguration> {
match DatabaseConfiguration::postgres()? {
Some(configuration) => Ok(configuration),
None => {
if get_env_with_default::<bool>(OCKAM_SQLITE_IN_MEMORY, false)? {
Ok(DatabaseConfiguration::sqlite_in_memory())
} else {
Ok(DatabaseConfiguration::sqlite(
root_path.join("database.sqlite3").as_path(),
))
}
}
None => match mode {
CliStateMode::Persistent(root_path) => Ok(DatabaseConfiguration::sqlite(
root_path.join("database.sqlite3"),
)),
CliStateMode::InMemory => Ok(DatabaseConfiguration::sqlite_in_memory()),
},
}
}

/// If the postgres database is configured, return the postgres configuration
pub(super) fn make_application_database_configuration(
root_path: &Path,
mode: &CliStateMode,
) -> Result<DatabaseConfiguration> {
match DatabaseConfiguration::postgres()? {
Some(configuration) => Ok(configuration),
None => {
if get_env_with_default::<bool>(OCKAM_SQLITE_IN_MEMORY, false)? {
Ok(DatabaseConfiguration::sqlite_in_memory())
} else {
Ok(DatabaseConfiguration::sqlite(
root_path.join("application_database.sqlite3").as_path(),
))
}
}
None => match mode {
CliStateMode::Persistent(root_path) => Ok(DatabaseConfiguration::sqlite(
root_path.join("application_database.sqlite3"),
)),
CliStateMode::InMemory => Ok(DatabaseConfiguration::sqlite_in_memory()),
},
}
}

pub(super) fn make_node_dir_path(root_path: &Path, node_name: &str) -> PathBuf {
pub(super) fn make_node_dir_path(root_path: impl AsRef<Path>, node_name: &str) -> PathBuf {
Self::make_nodes_dir_path(root_path).join(node_name)
}

pub(super) fn make_command_log_path(root_path: &Path, command_name: &str) -> PathBuf {
pub(super) fn make_command_log_path(
root_path: impl AsRef<Path>,
command_name: &str,
) -> PathBuf {
Self::make_commands_log_dir_path(root_path).join(command_name)
}

pub(super) fn make_nodes_dir_path(root_path: &Path) -> PathBuf {
root_path.join("nodes")
pub(super) fn make_nodes_dir_path(root_path: impl AsRef<Path>) -> PathBuf {
root_path.as_ref().join("nodes")
}

pub(super) fn make_commands_log_dir_path(root_path: &Path) -> PathBuf {
root_path.join("commands")
pub(super) fn make_commands_log_dir_path(root_path: impl AsRef<Path>) -> PathBuf {
root_path.as_ref().join("commands")
}

/// Delete the state files
fn delete_at(root_path: &Path) -> Result<()> {
fn delete_at(root_path: &PathBuf) -> Result<()> {
// Delete nodes logs
let _ = std::fs::remove_dir_all(Self::make_nodes_dir_path(root_path));
// Delete command logs
let _ = std::fs::remove_dir_all(Self::make_commands_log_dir_path(root_path));
// Delete the nodes database, keep the application database
if let Some(path) = Self::make_database_configuration(root_path)?.path() {
if let Some(path) =
Self::make_database_configuration(&CliStateMode::Persistent(Cow::Borrowed(root_path)))?
.path()
{
std::fs::remove_file(path)?;
};
Ok(())
Expand All @@ -334,6 +351,18 @@ pub fn random_name() -> String {
petname::petname(2, "-").unwrap_or(hex::encode(random::<[u8; 4]>()))
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CliStateMode<'a> {
Persistent(Cow<'a, PathBuf>),
InMemory,
}

impl<'a> CliStateMode<'a> {
pub fn with_default_dir() -> Result<Self> {
Ok(Self::Persistent(Cow::Owned(CliState::default_dir()?)))
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -348,12 +377,10 @@ mod tests {
async fn test_reset() -> Result<()> {
let db_file = NamedTempFile::new().unwrap();
let cli_state_directory = db_file.path().parent().unwrap().join(random_name());
let db = SqlxDatabase::create(&CliState::make_database_configuration(
&cli_state_directory,
)?)
.await?;
let mode = CliStateMode::Persistent(Cow::Owned(cli_state_directory.clone()));
let db = SqlxDatabase::create(&CliState::make_database_configuration(&mode)?).await?;
db.drop_all_postgres_tables().await?;
let cli = CliState::create(cli_state_directory.clone()).await?;
let cli = CliState::create(mode).await?;

// create 2 vaults
// the second vault is using a separate file
Expand Down
12 changes: 6 additions & 6 deletions implementations/rust/ockam/ockam_api/src/cli_state/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl CliState {

pub fn backup_logs(&self, node_name: &str) -> Result<()> {
// Atm node dir only has logs
let node_dir = self.node_dir(node_name);
let node_dir = self.node_dir(node_name)?;

let now = now()?;

Expand Down Expand Up @@ -175,7 +175,7 @@ impl CliState {
}

// remove the node directory
let _ = std::fs::remove_dir_all(self.node_dir(node_name));
let _ = std::fs::remove_dir_all(self.node_dir(node_name)?);
debug!(name=%node_name, "node deleted");
Ok(())
}
Expand Down Expand Up @@ -483,7 +483,7 @@ impl CliState {

/// Create a directory used to store files specific to a node
fn create_node_dir(&self, node_name: &str) -> Result<PathBuf> {
let path = self.node_dir(node_name);
let path = self.node_dir(node_name)?;
std::fs::create_dir_all(&path)?;
Ok(path)
}
Expand All @@ -497,8 +497,8 @@ impl CliState {
}

/// Return the directory used by a node
pub fn node_dir(&self, node_name: &str) -> PathBuf {
Self::make_node_dir_path(&self.dir(), node_name)
pub fn node_dir(&self, node_name: &str) -> Result<PathBuf> {
Ok(Self::make_node_dir_path(self.dir()?, node_name))
}

/// Return a log path to be used for a given command
Expand Down Expand Up @@ -788,7 +788,7 @@ mod tests {
"the node information is not available anymore"
);
assert!(
!cli.node_dir(node1).exists(),
!cli.node_dir(node1).unwrap().exists(),
"the node directory must be deleted"
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::cli_state::Result;
use crate::cli_state::{random_name, CliState, CliStateError};
use crate::cli_state::{CliStateMode, Result};
use ockam_node::database::SqlxDatabase;
use std::borrow::Cow;
use std::path::PathBuf;

/// Test support
Expand All @@ -10,12 +11,13 @@ impl CliState {
/// all previous state if the database being used is Postgres.
pub async fn test() -> Result<Self> {
let test_dir = Self::test_dir()?;
let mode = CliStateMode::Persistent(Cow::Owned(test_dir));

// clean the existing state if any
let db = SqlxDatabase::create(&CliState::make_database_configuration(&test_dir)?).await?;
let db = SqlxDatabase::create(&CliState::make_database_configuration(&mode)?).await?;
db.drop_all_postgres_tables().await?;

Self::create(test_dir).await
Self::create(mode).await
}

/// Return a test CliState with a random root directory
Expand All @@ -24,7 +26,8 @@ impl CliState {
/// any previous state if the database being used is Postgres.
pub async fn system() -> Result<Self> {
let test_dir = Self::test_dir()?;
Self::create(test_dir).await
let mode = CliStateMode::Persistent(Cow::Owned(test_dir));
Self::create(mode).await
}

/// Return a random root directory
Expand Down
Loading

0 comments on commit 9389b26

Please sign in to comment.