Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(multitenancy): add tenant_id as a field for data pipeline and support individual database for clickhouse #4867

Merged
merged 88 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
85e3676
feat(multitenancy): add logical sepration of tenant using db schema
jagan-jaya Apr 30, 2024
2265882
feat(multitenancy): add base_url for redirection and pay start
jagan-jaya May 13, 2024
50559b7
feat(multitenancy): format code and remove unused deps
jagan-jaya May 13, 2024
54c1aee
feat(multitenancy): create sessionstate for scheduler
jagan-jaya May 13, 2024
f6d3dac
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 14, 2024
7d35c89
chore: run formatter
hyperswitch-bot[bot] May 14, 2024
b2b05c3
feat(multitenancy): update tenants
jagan-jaya May 14, 2024
4a5748c
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya May 14, 2024
e60f9b5
feat(multitenancy): fix clippy warnings
jagan-jaya May 15, 2024
c1602da
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 15, 2024
978fbe4
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 17, 2024
d707357
feat(multitenancy): fix clippy warnings
jagan-jaya May 17, 2024
c9405db
feat(multitenancy): fix clippy warnings
jagan-jaya May 17, 2024
dda08c8
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 17, 2024
c376ffc
chore: run formatter
hyperswitch-bot[bot] May 17, 2024
c78729e
feat(multitenancy): add support to enable/disable multitenancy support
jagan-jaya May 17, 2024
66d8d4d
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya May 17, 2024
f103acc
fix: clear redis entry on update operation
jagan-jaya May 21, 2024
b3609b8
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 21, 2024
4e941d6
chore: run formatter
hyperswitch-bot[bot] May 21, 2024
f852184
feat: add tenant support in in-memory cache
jagan-jaya May 23, 2024
9e27425
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya May 23, 2024
6a174a2
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 23, 2024
e0cb6f0
feat: add tenant support in in-memory cache
jagan-jaya May 23, 2024
a6d1936
feat: address PR comments
jagan-jaya May 27, 2024
69f5fb4
feat: address PR comments
jagan-jaya May 27, 2024
18a75c0
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 27, 2024
983068d
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 27, 2024
d740d78
feat: add global tenant for users
jagan-jaya May 27, 2024
2a4bb9b
Merge branch 'multitenancy-users' of https://github.com/juspay/hypers…
jagan-jaya May 27, 2024
a1d7413
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya May 27, 2024
248bdf7
feat: add global tenant for users
jagan-jaya May 27, 2024
93aa1f9
fix: clippy warnings
jagan-jaya May 27, 2024
5bf788f
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya May 27, 2024
9516014
chore: run formatter
hyperswitch-bot[bot] May 27, 2024
dac602a
chore: run formatter
hyperswitch-bot[bot] May 27, 2024
827113f
fix: clippy warnings
jagan-jaya May 28, 2024
e6eea95
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya May 28, 2024
479bb2f
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 28, 2024
4cb732e
refactor: drainer to have single redis conn for error handling
jagan-jaya May 28, 2024
fb10f00
refactor: get redis key prefix from config
jagan-jaya May 29, 2024
6f57723
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 29, 2024
3688621
fix: clippy warnings
jagan-jaya May 29, 2024
4283f8f
fix: clippy warnings
jagan-jaya May 29, 2024
079f8c7
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 30, 2024
2afcf2c
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya May 30, 2024
07ea1e6
chore: run formatter
hyperswitch-bot[bot] May 30, 2024
8e1d9ad
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya May 30, 2024
c800622
feat(mulitenancy): add global tenant which handles users and other gl…
jagan-jaya May 30, 2024
8a45883
chore: run formatter
hyperswitch-bot[bot] May 30, 2024
083b637
fix: code formatting
jagan-jaya May 30, 2024
2004a02
Merge branch 'multitenancy-users' of https://github.com/juspay/hypers…
jagan-jaya May 30, 2024
5b1099f
fix: clippy warnings
jagan-jaya May 31, 2024
d5d5f84
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 3, 2024
d1a6a2f
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya Jun 3, 2024
745f7a6
fix: move use_key interface to global storage
jagan-jaya Jun 3, 2024
49e8a2e
chore: run formatter
hyperswitch-bot[bot] Jun 3, 2024
df02be4
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 3, 2024
3294ed8
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 3, 2024
1223f14
Merge branch 'main' into multitenancy
jarnura Jun 3, 2024
b2640c1
Merge branch 'multitenancy' of https://github.com/juspay/hyperswitch …
jagan-jaya Jun 3, 2024
7860ea1
feat(multitenancy): add clickhouse tenant
jagan-jaya Jun 4, 2024
75dc0dc
Merge branch 'multitenancy-users' of https://github.com/juspay/hypers…
jagan-jaya Jun 4, 2024
95ac878
Merge branch 'multitenancy-users' of https://github.com/juspay/hypers…
jagan-jaya Jun 4, 2024
691b88e
chore: run formatter
hyperswitch-bot[bot] Jun 4, 2024
983b71e
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 4, 2024
aeb1c21
Merge branch 'main' into multitenancy-users
jagan-jaya Jun 4, 2024
71b692e
Merge branch 'multitenancy-users' into multitenancy-analytics
jagan-jaya Jun 4, 2024
74af852
Merge branch 'main' into multitenancy-users
jagan-jaya Jun 4, 2024
f7cd486
feat(logs): add tenant id to logs
lsampras Jun 4, 2024
196c1df
chore: run formatter
hyperswitch-bot[bot] Jun 4, 2024
62ffbfd
feat(multitenancy): remove ununsed join functions for user_role_and_user
jagan-jaya Jun 5, 2024
a4151ee
Merge branch 'main' into multitenancy-users
jagan-jaya Jun 5, 2024
73718aa
Merge branch 'multitenancy-users' of https://github.com/juspay/hypers…
jagan-jaya Jun 5, 2024
ffdc727
fix(clippy): fix clippy warnings
jagan-jaya Jun 5, 2024
bc4dbf6
Merge branch 'main' into multitenancy-users
jagan-jaya Jun 5, 2024
bd91fa9
Merge branch 'multitenancy-users' of https://github.com/juspay/hypers…
jagan-jaya Jun 5, 2024
f15fc63
fix(clippy): fix clippy warnings
jagan-jaya Jun 5, 2024
93fa73f
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 6, 2024
2f0f882
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 6, 2024
02a8a2a
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 6, 2024
6e2fd46
feat(multitenancy): add seperate config for global schema
jagan-jaya Jun 7, 2024
e462c22
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 7, 2024
0eeff21
fix(multitenancy): move consts to common_utils
jagan-jaya Jun 13, 2024
1168417
Merge branch 'main' of https://github.com/juspay/hyperswitch into mul…
jagan-jaya Jun 13, 2024
5d5a2aa
chore: run formatter
hyperswitch-bot[bot] Jun 13, 2024
2f57dd4
fix(multitenancy): add global tenant config
jagan-jaya Jun 14, 2024
175b30c
fix(multitenancy): add clickhouse config from global store
jagan-jaya Jun 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ sdk_eligible_payment_methods = "card"

[multitenancy]
enabled = false
global_tenant = { schema = "public", redis_key_prefix = "" }

[multitenancy.tenants]
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""} # schema -> Postgres db schema, redis_key_prefix -> redis key distinguisher, base_url -> url of the tenant
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} # schema -> Postgres db schema, redis_key_prefix -> redis key distinguisher, base_url -> url of the tenant
3 changes: 2 additions & 1 deletion config/deployments/env_specific.toml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ region = "kms_region" # The AWS region used by the KMS SDK for decrypting data.

[multitenancy]
enabled = false
global_tenant = { schema = "public", redis_key_prefix = "" }

[multitenancy.tenants]
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""}
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"}
3 changes: 2 additions & 1 deletion config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ sdk_eligible_payment_methods = "card"

[multitenancy]
enabled = false
global_tenant = { schema = "public", redis_key_prefix = "" }

[multitenancy.tenants]
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""}
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"}
3 changes: 2 additions & 1 deletion config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ sdk_eligible_payment_methods = "card"

[multitenancy]
enabled = false
global_tenant = { schema = "public", redis_key_prefix = "" }

[multitenancy.tenants]
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""}
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"}
5 changes: 2 additions & 3 deletions crates/analytics/src/clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ pub type ClickhouseResult<T> = error_stack::Result<T, ClickhouseError>;
#[derive(Clone, Debug)]
pub struct ClickhouseClient {
pub config: Arc<ClickhouseConfig>,
pub database: String,
}

#[derive(Clone, Debug, serde::Deserialize)]
pub struct ClickhouseConfig {
username: String,
password: Option<String>,
host: String,
database_name: String,
}

impl Default for ClickhouseConfig {
Expand All @@ -51,7 +51,6 @@ impl Default for ClickhouseConfig {
username: "default".to_string(),
password: None,
host: "http://localhost:8123".to_string(),
database_name: "default".to_string(),
}
}
}
Expand All @@ -63,7 +62,7 @@ impl ClickhouseClient {
let params = CkhQuery {
date_time_output_format: String::from("iso"),
output_format_json_quote_64bit_integers: 0,
database: self.config.database_name.clone(),
database: self.database.clone(),
};
let response = client
.post(&self.config.host)
Expand Down
16 changes: 12 additions & 4 deletions crates/analytics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,22 +601,30 @@ impl AnalyticsProvider {
}
}

pub async fn from_conf(config: &AnalyticsConfig, tenant: &str) -> Self {
pub async fn from_conf(
config: &AnalyticsConfig,
tenant: &dyn storage_impl::config::ClickHouseConfig,
) -> Self {
match config {
AnalyticsConfig::Sqlx { sqlx } => Self::Sqlx(SqlxClient::from_conf(sqlx, tenant).await),
AnalyticsConfig::Sqlx { sqlx } => {
Self::Sqlx(SqlxClient::from_conf(sqlx, tenant.get_schema()).await)
}
AnalyticsConfig::Clickhouse { clickhouse } => Self::Clickhouse(ClickhouseClient {
config: Arc::new(clickhouse.clone()),
database: tenant.get_clickhouse_database().to_string(),
}),
AnalyticsConfig::CombinedCkh { sqlx, clickhouse } => Self::CombinedCkh(
SqlxClient::from_conf(sqlx, tenant).await,
SqlxClient::from_conf(sqlx, tenant.get_schema()).await,
ClickhouseClient {
config: Arc::new(clickhouse.clone()),
database: tenant.get_clickhouse_database().to_string(),
},
),
AnalyticsConfig::CombinedSqlx { sqlx, clickhouse } => Self::CombinedSqlx(
SqlxClient::from_conf(sqlx, tenant).await,
SqlxClient::from_conf(sqlx, tenant.get_schema()).await,
ClickhouseClient {
config: Arc::new(clickhouse.clone()),
database: tenant.get_clickhouse_database().to_string(),
},
),
}
Expand Down
4 changes: 2 additions & 2 deletions crates/common_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ pub const MAX_TTL_FOR_EXTENDED_CARD_INFO: u16 = 60 * 60 * 2;
/// Default tenant to be used when multitenancy is disabled
pub const DEFAULT_TENANT: &str = "public";

/// Global tenant to be used when multitenancy is enabled
pub const GLOBAL_TENANT: &str = "global";
/// Default tenant to be used when multitenancy is disabled
pub const TENANT_HEADER: &str = "x-tenant-id";

/// Max Length for MerchantReferenceId
pub const MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH: u8 = 64;
Expand Down
39 changes: 2 additions & 37 deletions crates/diesel_models/src/query/user.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
use async_bb8_diesel::AsyncRunQueryDsl;
use common_utils::pii;
use diesel::{
associations::HasTable, debug_query, result::Error as DieselError, ExpressionMethods,
JoinOnDsl, QueryDsl,
};
use error_stack::report;
use router_env::logger;
use diesel::{associations::HasTable, ExpressionMethods};
pub mod sample_data;

use crate::{
errors::{self},
query::generics,
schema::{
user_roles::{self, dsl as user_roles_dsl},
users::dsl as users_dsl,
},
user::*,
user_role::UserRole,
PgPooledConn, StorageResult,
query::generics, schema::users::dsl as users_dsl, user::*, PgPooledConn, StorageResult,
};

impl UserNew {
Expand Down Expand Up @@ -90,27 +76,6 @@ impl User {
.await
}

pub async fn find_joined_users_and_roles_by_merchant_id(
conn: &PgPooledConn,
mid: &str,
) -> StorageResult<Vec<(Self, UserRole)>> {
let query = Self::table()
.inner_join(user_roles::table.on(user_roles_dsl::user_id.eq(users_dsl::user_id)))
.filter(user_roles_dsl::merchant_id.eq(mid.to_owned()));

logger::debug!(query = %debug_query::<diesel::pg::Pg,_>(&query).to_string());

query
.get_results_async::<(Self, UserRole)>(conn)
.await
.map_err(|err| match err {
DieselError::NotFound => {
report!(err).change_context(errors::DatabaseError::NotFound)
}
_ => report!(err).change_context(errors::DatabaseError::Others),
})
}

pub async fn find_users_by_user_ids(
conn: &PgPooledConn,
user_ids: Vec<String>,
Expand Down
1 change: 1 addition & 0 deletions crates/drainer/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub struct Tenant {
pub base_url: String,
pub schema: String,
pub redis_key_prefix: String,
pub clickhouse_database: String,
}

#[derive(Debug, Deserialize, Clone)]
Expand Down
8 changes: 8 additions & 0 deletions crates/router/src/configs/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub struct Settings<S: SecretState> {
pub struct Multitenancy {
pub tenants: TenantConfig,
pub enabled: bool,
pub global_tenant: GlobalTenant,
}

impl Multitenancy {
Expand All @@ -152,6 +153,7 @@ pub struct Tenant {
pub base_url: String,
pub schema: String,
pub redis_key_prefix: String,
pub clickhouse_database: String,
}

impl storage_impl::config::TenantConfig for Tenant {
Expand All @@ -163,6 +165,12 @@ impl storage_impl::config::TenantConfig for Tenant {
}
}

impl storage_impl::config::ClickHouseConfig for Tenant {
fn get_clickhouse_database(&self) -> &str {
self.clickhouse_database.as_str()
}
}

#[derive(Debug, Deserialize, Clone, Default)]
pub struct GlobalTenant {
pub schema: String,
Expand Down
10 changes: 9 additions & 1 deletion crates/router/src/middleware.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use common_utils::consts::TENANT_HEADER;
use futures::StreamExt;
use router_env::{
logger,
Expand Down Expand Up @@ -140,10 +141,17 @@ where
// TODO: have a common source of truth for the list of top level fields
// /crates/router_env/src/logger/storage.rs also has a list of fields called PERSISTENT_KEYS
fn call(&self, req: actix_web::dev::ServiceRequest) -> Self::Future {
let tenant_id = req
.headers()
.get(TENANT_HEADER)
.and_then(|i| i.to_str().ok())
.map(|s| s.to_owned());
let response_fut = self.service.call(req);

Box::pin(
async move {
if let Some(tenant_id) = tenant_id {
router_env::tracing::Span::current().record("tenant_id", &tenant_id);
}
let response = response_fut.await;
router_env::tracing::Span::current().record("golden_log_line", true);
response
Expand Down
15 changes: 2 additions & 13 deletions crates/router/src/routes/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use actix_web::{web, Scope};
use api_models::routing::RoutingRetrieveQuery;
#[cfg(feature = "olap")]
use common_enums::TransactionType;
use common_utils::consts::{DEFAULT_TENANT, GLOBAL_TENANT};
#[cfg(feature = "email")]
use external_services::email::{ses::AwsSes, EmailService};
use external_services::file_storage::FileStorageInterface;
Expand Down Expand Up @@ -257,19 +256,11 @@ impl AppState {
let cache_store = get_cache_store(&conf.clone(), shut_down_signal, testable)
.await
.expect("Failed to create store");
let global_tenant = if conf.multitenancy.enabled {
GLOBAL_TENANT
} else {
DEFAULT_TENANT
};
let global_store: Box<dyn GlobalStorageInterface> = Self::get_store_interface(
&storage_impl,
&event_handler,
&conf,
&settings::GlobalTenant {
schema: global_tenant.to_string(),
redis_key_prefix: String::default(),
},
&conf.multitenancy.global_tenant,
Arc::clone(&cache_store),
testable,
)
Expand All @@ -288,9 +279,7 @@ impl AppState {
.get_storage_interface();
stores.insert(tenant_name.clone(), store);
#[cfg(feature = "olap")]
let pool =
AnalyticsProvider::from_conf(conf.analytics.get_inner(), tenant_name.as_str())
.await;
let pool = AnalyticsProvider::from_conf(conf.analytics.get_inner(), tenant).await;
#[cfg(feature = "olap")]
pools.insert(tenant_name.clone(), pool);
}
Expand Down
6 changes: 3 additions & 3 deletions crates/router/src/services/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use api_models::enums::{CaptureMethod, PaymentMethodType};
pub use client::{proxy_bypass_urls, ApiClient, MockApiClient, ProxyClient};
pub use common_utils::request::{ContentType, Method, Request, RequestBuilder};
use common_utils::{
consts::X_HS_LATENCY,
consts::{DEFAULT_TENANT, TENANT_HEADER, X_HS_LATENCY},
errors::{ErrorSwitch, ReportSwitchExt},
request::RequestContent,
};
Expand Down Expand Up @@ -941,10 +941,10 @@ where
.into_iter()
.collect();
let tenant_id = if !state.conf.multitenancy.enabled {
common_utils::consts::DEFAULT_TENANT.to_string()
DEFAULT_TENANT.to_string()
} else {
incoming_request_header
.get("x-tenant-id")
.get(TENANT_HEADER)
.and_then(|value| value.to_str().ok())
.ok_or_else(|| errors::ApiErrorResponse::MissingTenantId.switch())
.map(|req_tenant_id| {
Expand Down
4 changes: 4 additions & 0 deletions crates/storage_impl/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ pub trait TenantConfig: Send + Sync {
fn get_redis_key_prefix(&self) -> &str;
}

pub trait ClickHouseConfig: TenantConfig + Send + Sync {
fn get_clickhouse_database(&self) -> &str;
}

#[derive(Debug, serde::Deserialize, Clone, Copy, Default)]
#[serde(rename_all = "PascalCase")]
pub enum QueueStrategy {
Expand Down
3 changes: 2 additions & 1 deletion loadtest/config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ keys = "user-agent"

[multitenancy]
enabled = false
global_tenant = { schema = "public", redis_key_prefix = "" }

[multitenancy.tenants]
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""}
public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"}
Loading