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 8e5d9582e2f..b10a80307be 100644 --- a/config/development.toml +++ b/config/development.toml @@ -747,7 +747,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..60b720ae209 100644 --- a/crates/drainer/src/settings.rs +++ b/crates/drainer/src/settings.rs @@ -125,21 +125,57 @@ 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)] + #[serde(deny_unknown_fields)] + 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..f703eefe3db 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,39 @@ where })? } +impl<'de> Deserialize<'de> for TenantConfig { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + #[serde(deny_unknown_fields)] + 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 da1c70ebcfc..12dfe6e1624 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 22966208dd4..59979bf5adf 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -726,7 +726,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/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"