Skip to content

Commit

Permalink
Merge pull request #2719 from fermyon/integrate-spin-sqlite
Browse files Browse the repository at this point in the history
[Factors] Integrate sqlite into Trigger2
  • Loading branch information
rylev committed Aug 19, 2024
2 parents c32bdf0 + 3cafa2a commit acaac05
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 62 deletions.
38 changes: 20 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/factor-sqlite/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "factor-sqlite"
name = "spin-factor-sqlite"
version.workspace = true
authors.workspace = true
edition.workspace = true
Expand Down
4 changes: 3 additions & 1 deletion crates/factor-sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use spin_locked_app::MetadataKey;
use spin_world::v1::sqlite as v1;
use spin_world::v2::sqlite as v2;

pub use runtime_config::RuntimeConfig;

pub struct SqliteFactor {
default_label_resolver: Arc<dyn DefaultLabelResolver>,
}
Expand All @@ -29,7 +31,7 @@ impl SqliteFactor {
}

impl Factor for SqliteFactor {
type RuntimeConfig = runtime_config::RuntimeConfig;
type RuntimeConfig = RuntimeConfig;
type AppState = AppState;
type InstanceBuilder = InstanceState;

Expand Down
27 changes: 8 additions & 19 deletions crates/factor-sqlite/src/runtime_config/spin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,25 @@ use tokio::sync::OnceCell;

use crate::{Connection, ConnectionCreator, DefaultLabelResolver};

/// Spin's default handling of the runtime configuration for SQLite databases.
/// Spin's default resolution of runtime configuration for SQLite databases.
///
/// This type implements the [`RuntimeConfigResolver`] trait and provides a way to
/// opt into the default behavior of Spin's SQLite database handling.
pub struct SpinSqliteRuntimeConfig {
/// This type implements how Spin CLI's SQLite implementation is configured
/// through the runtime config toml as well as the behavior of the "default" label.
pub struct RuntimeConfigResolver {
default_database_dir: PathBuf,
local_database_dir: PathBuf,
}

impl SpinSqliteRuntimeConfig {
impl RuntimeConfigResolver {
/// Create a new `SpinSqliteRuntimeConfig`
///
/// This takes as arguments:
/// * the directory to use as the default location for SQLite databases.
/// Usually this will be the path to the `.spin` state directory.
/// * the *absolute* path to the directory from which relative paths to
/// * the path to the directory from which relative paths to
/// local SQLite databases are resolved. (this should most likely be the
/// path to the runtime-config file or the current working dir).
///
/// Panics if either `default_database_dir` or `local_database_dir` are not
/// absolute paths.
pub fn new(default_database_dir: PathBuf, local_database_dir: PathBuf) -> Self {
assert!(
default_database_dir.is_absolute(),
"default_database_dir must be an absolute path"
);
assert!(
local_database_dir.is_absolute(),
"local_database_dir must be an absolute path"
);
Self {
default_database_dir,
local_database_dir,
Expand All @@ -59,7 +48,7 @@ impl SpinSqliteRuntimeConfig {
/// type = "$database-type"
/// ... extra type specific configuration ...
/// ```
pub fn config_from_table<T: GetTomlValue>(
pub fn resolve_from_toml<T: GetTomlValue>(
&self,
table: &T,
) -> anyhow::Result<Option<super::RuntimeConfig>> {
Expand Down Expand Up @@ -106,7 +95,7 @@ pub struct RuntimeConfig {
pub config: toml::Table,
}

impl DefaultLabelResolver for SpinSqliteRuntimeConfig {
impl DefaultLabelResolver for RuntimeConfigResolver {
fn default(&self, label: &str) -> Option<Arc<dyn ConnectionCreator>> {
// Only default the database labeled "default".
if label != "default" {
Expand Down
21 changes: 11 additions & 10 deletions crates/factor-sqlite/tests/factor_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashSet, sync::Arc};

use factor_sqlite::{runtime_config::spin::SpinSqliteRuntimeConfig, SqliteFactor};
use spin_factor_sqlite::{runtime_config::spin::RuntimeConfigResolver, SqliteFactor};
use spin_factors::{
anyhow::{self, bail, Context},
runtime_config::toml::TomlKeyTracker,
Expand Down Expand Up @@ -66,7 +66,7 @@ async fn no_error_when_database_is_configured() -> anyhow::Result<()> {
[sqlite_database.foo]
type = "spin"
};
let sqlite_config = SpinSqliteRuntimeConfig::new("/".into(), "/".into());
let sqlite_config = RuntimeConfigResolver::new("/".into(), "/".into());
let env = TestEnvironment::new(factors)
.extend_manifest(toml! {
[component.test-component]
Expand All @@ -82,14 +82,14 @@ async fn no_error_when_database_is_configured() -> anyhow::Result<()> {

struct TomlRuntimeSource<'a> {
table: TomlKeyTracker<'a>,
sqlite_config: SpinSqliteRuntimeConfig,
runtime_config_resolver: RuntimeConfigResolver,
}

impl<'a> TomlRuntimeSource<'a> {
fn new(table: &'a toml::Table, sqlite_config: SpinSqliteRuntimeConfig) -> Self {
fn new(table: &'a toml::Table, runtime_config_resolver: RuntimeConfigResolver) -> Self {
Self {
table: TomlKeyTracker::new(table),
sqlite_config,
runtime_config_resolver,
}
}
}
Expand All @@ -98,7 +98,7 @@ impl FactorRuntimeConfigSource<SqliteFactor> for TomlRuntimeSource<'_> {
fn get_runtime_config(
&mut self,
) -> anyhow::Result<Option<<SqliteFactor as Factor>::RuntimeConfig>> {
self.sqlite_config.config_from_table(&self.table)
self.runtime_config_resolver.resolve_from_toml(&self.table)
}
}

Expand Down Expand Up @@ -129,8 +129,8 @@ impl DefaultLabelResolver {
}
}

impl factor_sqlite::DefaultLabelResolver for DefaultLabelResolver {
fn default(&self, label: &str) -> Option<Arc<dyn factor_sqlite::ConnectionCreator>> {
impl spin_factor_sqlite::DefaultLabelResolver for DefaultLabelResolver {
fn default(&self, label: &str) -> Option<Arc<dyn spin_factor_sqlite::ConnectionCreator>> {
let Some(default) = &self.default else {
return None;
};
Expand All @@ -142,10 +142,11 @@ impl factor_sqlite::DefaultLabelResolver for DefaultLabelResolver {
struct InvalidConnectionCreator;

#[async_trait::async_trait]
impl factor_sqlite::ConnectionCreator for InvalidConnectionCreator {
impl spin_factor_sqlite::ConnectionCreator for InvalidConnectionCreator {
async fn create_connection(
&self,
) -> Result<Box<dyn factor_sqlite::Connection + 'static>, spin_world::v2::sqlite::Error> {
) -> Result<Box<dyn spin_factor_sqlite::Connection + 'static>, spin_world::v2::sqlite::Error>
{
Err(spin_world::v2::sqlite::Error::InvalidConnection)
}
}
1 change: 1 addition & 0 deletions crates/runtime-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ spin-factor-key-value-redis = { path = "../factor-key-value-redis" }
spin-factor-key-value-azure = { path = "../factor-key-value-azure" }
spin-factor-outbound-http = { path = "../factor-outbound-http" }
spin-factor-outbound-networking = { path = "../factor-outbound-networking" }
spin-factor-sqlite = { path = "../factor-sqlite" }
spin-factor-wasi = { path = "../factor-wasi" }
toml = "0.8"

Expand Down
68 changes: 58 additions & 10 deletions crates/runtime-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use spin_factor_key_value::{DefaultLabelResolver as _, KeyValueFactor};
use spin_factor_outbound_http::OutboundHttpFactor;
use spin_factor_outbound_networking::runtime_config::spin::SpinTlsRuntimeConfig;
use spin_factor_outbound_networking::OutboundNetworkingFactor;
use spin_factor_sqlite::runtime_config::spin as sqlite;
use spin_factor_sqlite::SqliteFactor;
use spin_factor_wasi::WasiFactor;
use spin_factors::{
runtime_config::toml::TomlKeyTracker, FactorRuntimeConfigSource, RuntimeConfigSourceFinalizer,
Expand All @@ -17,12 +19,13 @@ pub const DEFAULT_STATE_DIR: &str = ".spin";
/// A runtime configuration which has been resolved from a runtime config source.
///
/// Includes other pieces of configuration that are used to resolve the runtime configuration.
#[derive(Default)]
pub struct ResolvedRuntimeConfig<T> {
/// The resolved runtime configuration.
pub runtime_config: T,
/// The resolver used to resolve key-value stores from runtime configuration.
pub key_value_resolver: key_value::RuntimeConfigResolver,
/// The resolver used to resolve sqlite databases from runtime configuration.
pub sqlite_resolver: sqlite::RuntimeConfigResolver,
}

impl<T> ResolvedRuntimeConfig<T>
Expand All @@ -32,9 +35,12 @@ where
{
/// Creates a new resolved runtime configuration from a runtime config source TOML file.
pub fn from_file(runtime_config_path: &Path, state_dir: Option<&str>) -> anyhow::Result<Self> {
let key_value_resolver =
key_value_resolver(PathBuf::from(state_dir.unwrap_or(DEFAULT_STATE_DIR)));
let tls_resolver = SpinTlsRuntimeConfig::new(runtime_config_path);
let key_value_config_resolver =
key_value_config_resolver(PathBuf::from(state_dir.unwrap_or(DEFAULT_STATE_DIR)));

let sqlite_config_resolver =
sqlite_config_resolver(state_dir).context("failed to resolve sqlite runtime config")?;

let file = std::fs::read_to_string(runtime_config_path).with_context(|| {
format!(
Expand All @@ -48,14 +54,19 @@ where
runtime_config_path.display()
)
})?;
let runtime_config: T =
TomlRuntimeConfigSource::new(&toml, &key_value_resolver, &tls_resolver)
.try_into()
.map_err(Into::into)?;
let runtime_config: T = TomlRuntimeConfigSource::new(
&toml,
&key_value_config_resolver,
&tls_resolver,
&sqlite_config_resolver,
)
.try_into()
.map_err(Into::into)?;

Ok(Self {
runtime_config,
key_value_resolver,
key_value_resolver: key_value_config_resolver,
sqlite_resolver: sqlite_config_resolver,
})
}

Expand All @@ -81,23 +92,37 @@ where
}
}

impl<T: Default> ResolvedRuntimeConfig<T> {
pub fn default(state_dir: Option<&str>) -> Self {
Self {
sqlite_resolver: sqlite_config_resolver(state_dir)
.expect("failed to resolve sqlite runtime config"),
key_value_resolver: Default::default(),
runtime_config: Default::default(),
}
}
}

/// The TOML based runtime configuration source Spin CLI.
pub struct TomlRuntimeConfigSource<'a> {
table: TomlKeyTracker<'a>,
key_value: &'a key_value::RuntimeConfigResolver,
tls: &'a SpinTlsRuntimeConfig,
sqlite: &'a sqlite::RuntimeConfigResolver,
}

impl<'a> TomlRuntimeConfigSource<'a> {
pub fn new(
table: &'a toml::Table,
key_value: &'a key_value::RuntimeConfigResolver,
tls: &'a SpinTlsRuntimeConfig,
sqlite: &'a sqlite::RuntimeConfigResolver,
) -> Self {
Self {
table: TomlKeyTracker::new(table),
key_value,
tls,
sqlite,
}
}
}
Expand Down Expand Up @@ -131,6 +156,12 @@ impl FactorRuntimeConfigSource<OutboundHttpFactor> for TomlRuntimeConfigSource<'
}
}

impl FactorRuntimeConfigSource<SqliteFactor> for TomlRuntimeConfigSource<'_> {
fn get_runtime_config(&mut self) -> anyhow::Result<Option<spin_factor_sqlite::RuntimeConfig>> {
self.sqlite.resolve_from_toml(self.table.as_ref())
}
}

impl RuntimeConfigSourceFinalizer for TomlRuntimeConfigSource<'_> {
fn finalize(&mut self) -> anyhow::Result<()> {
Ok(self.table.validate_all_keys_used()?)
Expand All @@ -140,10 +171,12 @@ impl RuntimeConfigSourceFinalizer for TomlRuntimeConfigSource<'_> {
const DEFAULT_KEY_VALUE_STORE_FILENAME: &str = "sqlite_key_value.db";
const DEFAULT_KEY_VALUE_STORE_LABEL: &str = "default";

/// The key-value runtime configuration resolver used by the trigger.
/// The key-value runtime configuration resolver.
///
/// Takes a base path for the local store.
pub fn key_value_resolver(local_store_base_path: PathBuf) -> key_value::RuntimeConfigResolver {
pub fn key_value_config_resolver(
local_store_base_path: PathBuf,
) -> key_value::RuntimeConfigResolver {
let mut key_value = key_value::RuntimeConfigResolver::new();

// Register the supported store types.
Expand Down Expand Up @@ -173,3 +206,18 @@ pub fn key_value_resolver(local_store_base_path: PathBuf) -> key_value::RuntimeC

key_value
}

/// The sqlite runtime configuration resolver.
///
/// Takes a base path to the state directory.
fn sqlite_config_resolver(
state_dir: Option<&str>,
) -> anyhow::Result<sqlite::RuntimeConfigResolver> {
let default_database_dir = PathBuf::from(state_dir.unwrap_or(DEFAULT_STATE_DIR));
let local_database_dir =
std::env::current_dir().context("failed to get current working directory")?;
Ok(sqlite::RuntimeConfigResolver::new(
default_database_dir,
local_database_dir,
))
}
1 change: 1 addition & 0 deletions crates/trigger2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ spin-factor-outbound-http = { path = "../factor-outbound-http" }
spin-factor-outbound-networking = { path = "../factor-outbound-networking" }
spin-factor-wasi = { path = "../factor-wasi" }
spin-factor-key-value = { path = "../factor-key-value" }
spin-factor-sqlite = { path = "../factor-sqlite" }
spin-factors = { path = "../factors" }
spin-factors-executor = { path = "../factors-executor" }
spin-telemetry = { path = "../telemetry" }
Expand Down
Loading

0 comments on commit acaac05

Please sign in to comment.