From eca28ddaad1aa7af0b5e122d180481191ec85399 Mon Sep 17 00:00:00 2001 From: Kartikeya Hegde Date: Mon, 28 Oct 2024 16:22:44 +0530 Subject: [PATCH] fix(multitenancy): consistently use tenant nomenclature everywhere (#6389) --- config/config.example.toml | 2 +- config/deployments/env_specific.toml | 2 +- config/development.toml | 2 +- config/docker_compose.toml | 2 +- crates/drainer/src/settings.rs | 45 ++++++++++++++++-- crates/router/src/configs/settings.rs | 47 ++++++++++++++++--- .../router/src/core/payment_methods/cards.rs | 8 ++-- crates/router/src/core/routing/helpers.rs | 2 +- crates/router/src/middleware.rs | 7 +-- crates/router/src/routes/app.rs | 2 +- crates/router/src/services/api.rs | 32 ++++++------- .../src/types/storage/payment_attempt.rs | 6 +-- loadtest/config/development.toml | 2 +- 13 files changed, 113 insertions(+), 46 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 8f04ba49831..b0d3c743673 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -741,7 +741,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants] -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 +public = { 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 [user_auth_methods] encryption_key = "" # Encryption key used for encrypting data in user_authentication_methods table diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml index cfefe9a130f..0eab330652a 100644 --- a/config/deployments/env_specific.toml +++ b/config/deployments/env_specific.toml @@ -305,7 +305,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } [user_auth_methods] encryption_key = "user_auth_table_encryption_key" # Encryption key used for encrypting data in user_authentication_methods table diff --git a/config/development.toml b/config/development.toml index d32c3610132..274e605193f 100644 --- a/config/development.toml +++ b/config/development.toml @@ -750,7 +750,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [user_auth_methods] encryption_key = "A8EF32E029BC3342E54BF2E172A4D7AA43E8EF9D2C3A624A9F04E2EF79DC698F" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index dde0902af91..c8436efd022 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -575,7 +575,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default" } [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } [user_auth_methods] encryption_key = "A8EF32E029BC3342E54BF2E172A4D7AA43E8EF9D2C3A624A9F04E2EF79DC698F" diff --git a/crates/drainer/src/settings.rs b/crates/drainer/src/settings.rs index 05226739504..5b391b492e0 100644 --- a/crates/drainer/src/settings.rs +++ b/crates/drainer/src/settings.rs @@ -125,21 +125,56 @@ impl Multitenancy { pub fn get_tenants(&self) -> &HashMap { &self.tenants.0 } - pub fn get_tenant_names(&self) -> Vec { - self.tenants.0.keys().cloned().collect() + pub fn get_tenant_ids(&self) -> Vec { + self.tenants + .0 + .values() + .map(|tenant| tenant.tenant_id.clone()) + .collect() } pub fn get_tenant(&self, tenant_id: &str) -> Option<&Tenant> { self.tenants.0.get(tenant_id) } } -#[derive(Debug, Deserialize, Clone, Default)] -#[serde(transparent)] +#[derive(Debug, Clone, Default)] pub struct TenantConfig(pub HashMap); +impl<'de> Deserialize<'de> for TenantConfig { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + struct Inner { + base_url: String, + schema: String, + redis_key_prefix: String, + clickhouse_database: String, + } + + let hashmap = >::deserialize(deserializer)?; + + Ok(Self( + hashmap + .into_iter() + .map(|(key, value)| { + ( + key.clone(), + Tenant { + tenant_id: key, + base_url: value.base_url, + schema: value.schema, + redis_key_prefix: value.redis_key_prefix, + clickhouse_database: value.clickhouse_database, + }, + ) + }) + .collect(), + )) + } +} + #[derive(Debug, Deserialize, Clone, Default)] pub struct Tenant { - pub name: String, + pub tenant_id: String, pub base_url: String, pub schema: String, pub redis_key_prefix: String, diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index 149ee2b8456..61e026ae2c5 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -141,8 +141,12 @@ impl Multitenancy { pub fn get_tenants(&self) -> &HashMap { &self.tenants.0 } - pub fn get_tenant_names(&self) -> Vec { - self.tenants.0.keys().cloned().collect() + pub fn get_tenant_ids(&self) -> Vec { + self.tenants + .0 + .values() + .map(|tenant| tenant.tenant_id.clone()) + .collect() } pub fn get_tenant(&self, tenant_id: &str) -> Option<&Tenant> { self.tenants.0.get(tenant_id) @@ -154,13 +158,12 @@ pub struct DecisionConfig { pub base_url: String, } -#[derive(Debug, Deserialize, Clone, Default)] -#[serde(transparent)] +#[derive(Debug, Clone, Default)] pub struct TenantConfig(pub HashMap); -#[derive(Debug, Deserialize, Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct Tenant { - pub name: String, + pub tenant_id: String, pub base_url: String, pub schema: String, pub redis_key_prefix: String, @@ -1102,6 +1105,38 @@ where })? } +impl<'de> Deserialize<'de> for TenantConfig { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + struct Inner { + base_url: String, + schema: String, + redis_key_prefix: String, + clickhouse_database: String, + } + + let hashmap = >::deserialize(deserializer)?; + + Ok(Self( + hashmap + .into_iter() + .map(|(key, value)| { + ( + key.clone(), + Tenant { + tenant_id: key, + base_url: value.base_url, + schema: value.schema, + redis_key_prefix: value.redis_key_prefix, + clickhouse_database: value.clickhouse_database, + }, + ) + }) + .collect(), + )) + } +} + #[cfg(test)] mod hashmap_deserialization_test { #![allow(clippy::unwrap_used)] diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 067b35e1e5e..990a0f0e9ad 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2058,7 +2058,7 @@ pub async fn get_payment_method_from_hs_locker<'a>( merchant_id, payment_method_reference, locker_choice, - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await @@ -2112,7 +2112,7 @@ pub async fn add_card_to_hs_locker( locker, payload, locker_choice, - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await?; @@ -2309,7 +2309,7 @@ pub async fn get_card_from_hs_locker<'a>( merchant_id, card_reference, Some(locker_choice), - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await @@ -2355,7 +2355,7 @@ pub async fn delete_card_from_hs_locker<'a>( customer_id, merchant_id, card_reference, - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 6b584583174..31cd4234714 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -739,7 +739,7 @@ pub async fn push_metrics_for_success_based_routing( &metrics::CONTEXT, 1, &add_attributes([ - ("tenant", state.tenant.name.clone()), + ("tenant", state.tenant.tenant_id.clone()), ( "merchant_id", payment_attempt.merchant_id.get_string_repr().to_string(), diff --git a/crates/router/src/middleware.rs b/crates/router/src/middleware.rs index c80d14b9e25..0185d8a0768 100644 --- a/crates/router/src/middleware.rs +++ b/crates/router/src/middleware.rs @@ -147,10 +147,11 @@ where .and_then(|i| i.to_str().ok()) .map(|s| s.to_owned()); let response_fut = self.service.call(req); + let tenant_id_clone = tenant_id.clone(); Box::pin( async move { - if let Some(tenant_id) = tenant_id { - router_env::tracing::Span::current().record("tenant_id", &tenant_id); + if let Some(tenant) = tenant_id_clone { + router_env::tracing::Span::current().record("tenant_id", tenant); } let response = response_fut.await; router_env::tracing::Span::current().record("golden_log_line", true); @@ -166,7 +167,7 @@ where status_code = Empty, flow = "UNKNOWN", golden_log_line = Empty, - tenant_id = "ta" + tenant_id = &tenant_id ) .or_current(), ), diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 33699ed266a..f11840edf63 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -207,7 +207,7 @@ pub struct AppState { } impl scheduler::SchedulerAppState for AppState { fn get_tenants(&self) -> Vec { - self.conf.multitenancy.get_tenant_names() + self.conf.multitenancy.get_tenant_ids() } } pub trait AppStateInfo { diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 6f6eb381669..02d4950a47d 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -721,31 +721,27 @@ where .change_context(errors::ApiErrorResponse::InternalServerError.switch())?; let mut event_type = payload.get_api_event_type(); - let tenants: HashSet<_> = state - .conf - .multitenancy - .get_tenant_names() - .into_iter() - .collect(); let tenant_id = if !state.conf.multitenancy.enabled { DEFAULT_TENANT.to_string() } else { - incoming_request_header + let request_tenant_id = incoming_request_header .get(TENANT_HEADER) .and_then(|value| value.to_str().ok()) - .ok_or_else(|| errors::ApiErrorResponse::MissingTenantId.switch()) - .map(|req_tenant_id| { - if !tenants.contains(req_tenant_id) { - Err(errors::ApiErrorResponse::InvalidTenant { - tenant_id: req_tenant_id.to_string(), - } - .switch()) - } else { - Ok(req_tenant_id.to_string()) + .ok_or_else(|| errors::ApiErrorResponse::MissingTenantId.switch())?; + + state + .conf + .multitenancy + .get_tenant(request_tenant_id) + .map(|tenant| tenant.tenant_id.clone()) + .ok_or( + errors::ApiErrorResponse::InvalidTenant { + tenant_id: request_tenant_id.to_string(), } - })?? + .switch(), + )? }; - // let tenant_id = "public".to_string(); + let mut session_state = Arc::new(app_state.clone()).get_session_state(tenant_id.as_str(), || { errors::ApiErrorResponse::InvalidTenant { diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 98f51725bbe..0291374d54f 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -221,7 +221,7 @@ mod tests { let store = state .stores - .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .get(state.conf.multitenancy.get_tenant_ids().first().unwrap()) .unwrap(); let response = store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) @@ -304,7 +304,7 @@ mod tests { }; let store = state .stores - .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .get(state.conf.multitenancy.get_tenant_ids().first().unwrap()) .unwrap(); store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) @@ -401,7 +401,7 @@ mod tests { }; let store = state .stores - .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .get(state.conf.multitenancy.get_tenant_ids().first().unwrap()) .unwrap(); store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index c8a5ccf9228..11268e15e54 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -369,7 +369,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "" } [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [email] sender_email = "example@example.com"