Skip to content

Commit

Permalink
feat: Tenant specific config support via .cac.toml
Browse files Browse the repository at this point in the history
  • Loading branch information
ayushjain17 committed Sep 27, 2024
1 parent 8b68900 commit 99c5707
Show file tree
Hide file tree
Showing 16 changed files with 429 additions and 307 deletions.
3 changes: 0 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,10 @@ CAC_HOST="http://localhost:8080"
API_HOSTNAME="http://localhost:8080"
SUPERPOSITION_VERSION="v0.1.0"
HOSTNAME="<application_name>-<deployment_id>-<replicaset>-<pod>"
MJOS_ALLOWED_ORIGINS=https://potato.in,https://onion.in,http://localhost:8080
ACTIX_KEEP_ALIVE=120
MAX_DB_CONNECTION_POOL_SIZE=3
ENABLE_TENANT_AND_SCOPE=true
TENANTS=dev,test
TENANT_MIDDLEWARE_EXCLUSION_LIST="/health,/assets/favicon.ico,/pkg/frontend.js,/pkg,/pkg/frontend_bg.wasm,/pkg/tailwind.css,/pkg/style.css,/assets,/admin,/"
SERVICE_PREFIX=""
SERVICE_NAME="CAC"
MANDATORY_DIMENSIONS=""
# MANDATORY_DIMENSIONS="dev:clientId,fare;test:fare"
2 changes: 2 additions & 0 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/cac_toml/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ path = "src/bin.rs"
clap = { version = "4.3.0", features = ["derive"] }
pest = "2.6"
pest_derive = "2.6"
toml = { version = "0.8.8", features = ["preserve_order"] }
toml = { workspace = true }
48 changes: 23 additions & 25 deletions crates/context_aware_config/src/api/config/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
use std::{collections::HashMap, str::FromStr};

use super::helpers::{
filter_config_by_dimensions, filter_config_by_prefix, get_query_params_map,
};
use super::types::{Config, Context};
use crate::api::context::{
delete_context_api, hash, put, validate_dimensions_and_calculate_priority, PutReq,
};
use crate::api::dimension::get_all_dimension_schema_map;
use crate::{
db::schema::{config_versions::dsl as config_versions, event_log::dsl as event_log},
helpers::generate_cac,
};
use actix_http::header::HeaderValue;
use actix_web::web::Data;
use actix_web::{get, put, web, HttpRequest, HttpResponse, HttpResponseBuilder, Scope};
use cac_client::{eval_cac, eval_cac_with_reasoning, MergeStrategy};
use chrono::{DateTime, NaiveDateTime, TimeZone, Timelike, Utc};
Expand All @@ -22,19 +9,33 @@ use diesel::{
r2d2::{ConnectionManager, PooledConnection},
ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl,
};
use serde_json::{json, Map, Value};
use service_utils::service::types::{AppState, Tenant};
use superposition_macros::{bad_argument, db_error, unexpected_error};
use superposition_types::{result as superposition, Cac, Condition, Overrides, User};

use itertools::Itertools;
use jsonschema::JSONSchema;
use serde_json::{json, Map, Value};
use service_utils::{
helpers::extract_dimensions,
service::types::{AppHeader, DbConnection},
};
use superposition_macros::{bad_argument, db_error, unexpected_error};
use superposition_types::{
result as superposition, Cac, Condition, Overrides, TenantConfig, User,
};
use uuid::Uuid;

use crate::api::context::{
delete_context_api, hash, put, validate_dimensions_and_calculate_priority, PutReq,
};
use crate::api::dimension::get_all_dimension_schema_map;
use crate::{
db::schema::{config_versions::dsl as config_versions, event_log::dsl as event_log},
helpers::generate_cac,
};

use super::helpers::{
filter_config_by_dimensions, filter_config_by_prefix, get_query_params_map,
};
use super::types::{Config, Context};

pub fn endpoints() -> Scope {
Scope::new("")
.service(get)
Expand Down Expand Up @@ -365,8 +366,7 @@ fn construct_new_payload(
async fn reduce_config_key(
user: User,
conn: &mut PooledConnection<ConnectionManager<PgConnection>>,
state: &Data<AppState>,
tenant: &Tenant,
tenant_config: &TenantConfig,
mut og_contexts: Vec<Context>,
mut og_overrides: HashMap<String, Overrides>,
check_key: &str,
Expand Down Expand Up @@ -454,7 +454,7 @@ async fn reduce_config_key(
if is_approve {
let _ = delete_context_api(cid.clone(), user.clone(), conn);
if let Ok(put_req) = construct_new_payload(request_payload) {
let _ = put(put_req, conn, false, &user, state, tenant);
let _ = put(put_req, conn, false, &user, &tenant_config);
}
}

Expand Down Expand Up @@ -497,8 +497,7 @@ async fn reduce_config(
req: HttpRequest,
user: User,
db_conn: DbConnection,
state: Data<AppState>,
tenant: Tenant,
tenant_config: TenantConfig,
) -> superposition::Result<HttpResponse> {
let DbConnection(mut conn) = db_conn;
let is_approve = req
Expand All @@ -517,8 +516,7 @@ async fn reduce_config(
config = reduce_config_key(
user.clone(),
&mut conn,
&state,
&tenant,
&tenant_config,
contexts.clone(),
overrides.clone(),
key.as_str(),
Expand Down
122 changes: 56 additions & 66 deletions crates/context_aware_config/src/api/context/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
extern crate base64;

use std::collections::HashMap;
use std::str;

use crate::helpers::{
add_config_version, calculate_context_priority, json_to_sorted_string,
validate_context_jsonschema,
use actix_web::{
delete, get, post, put,
web::{Data, Json, Path, Query},
HttpResponse, Responder, Scope,
};
use chrono::Utc;
use diesel::{
delete,
r2d2::{ConnectionManager, PooledConnection},
result::{DatabaseErrorKind::*, Error::DatabaseError},
upsert::excluded,
Connection, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl,
};
use jsonschema::{Draft, JSONSchema, ValidationError};
use serde_json::{from_value, json, Map, Value};
use service_utils::{
helpers::{parse_config_tags, validation_err_to_str},
service::types::{AppHeader, AppState, CustomHeaders, DbConnection},
};
use superposition_macros::{
bad_argument, db_error, not_found, unexpected_error, validation_error,
};
use superposition_types::{
result as superposition, SuperpositionUser, TenantConfig, User,
};

use crate::{
api::{
context::types::{
Expand All @@ -20,40 +44,17 @@ use crate::{
default_configs::dsl,
},
},
helpers::{
add_config_version, calculate_context_priority, json_to_sorted_string,
validate_context_jsonschema,
},
};
use actix_web::web::Data;
use service_utils::service::types::{AppHeader, AppState, CustomHeaders, Tenant};

use actix_web::{
delete, get, post, put,
web::{Json, Path, Query},
HttpResponse, Responder, Scope,
};
use chrono::Utc;
use diesel::{
delete,
r2d2::{ConnectionManager, PooledConnection},
result::{DatabaseErrorKind::*, Error::DatabaseError},
upsert::excluded,
Connection, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl,
};
use jsonschema::{Draft, JSONSchema, ValidationError};
use serde_json::{from_value, json, Map, Value};
use service_utils::helpers::{parse_config_tags, validation_err_to_str};
use service_utils::service::types::DbConnection;
use std::collections::HashMap;
use superposition_types::{SuperpositionUser, User};

use super::helpers::{
validate_condition_with_functions, validate_condition_with_mandatory_dimensions,
validate_override_with_functions,
};

use superposition_macros::{
bad_argument, db_error, not_found, unexpected_error, validation_error,
};
use superposition_types::result as superposition;

pub fn endpoints() -> Scope {
Scope::new("")
.service(put_handler)
Expand Down Expand Up @@ -193,17 +194,15 @@ fn create_ctx_from_put_req(
req: Json<PutReq>,
conn: &mut DBConnection,
user: &User,
state: &Data<AppState>,
tenant: &Tenant,
tenant_config: &TenantConfig,
) -> superposition::Result<Context> {
let ctx_condition = req.context.to_owned().into_inner();
let condition_val = json!(ctx_condition);
let r_override = req.r#override.clone().into_inner();
let ctx_override = json!(r_override.to_owned());
validate_condition_with_mandatory_dimensions(
&ctx_condition,
&state.mandatory_dimensions,
tenant,
&tenant_config.mandatory_dimensions,
)?;
validate_override_with_default_configs(conn, &r_override)?;
validate_condition_with_functions(conn, &ctx_condition)?;
Expand Down Expand Up @@ -307,11 +306,10 @@ pub fn put(
conn: &mut PooledConnection<ConnectionManager<PgConnection>>,
already_under_txn: bool,
user: &User,
state: &Data<AppState>,
tenant: &Tenant,
tenant_config: &TenantConfig,
) -> superposition::Result<PutResp> {
use contexts::dsl::contexts;
let new_ctx = create_ctx_from_put_req(req, conn, user, &state, tenant)?;
let new_ctx = create_ctx_from_put_req(req, conn, user, tenant_config)?;

if already_under_txn {
diesel::sql_query("SAVEPOINT put_ctx_savepoint").execute(conn)?;
Expand Down Expand Up @@ -340,11 +338,11 @@ async fn put_handler(
req: Json<PutReq>,
mut db_conn: DbConnection,
user: User,
tenant: Tenant,
tenant_config: TenantConfig,
) -> superposition::Result<HttpResponse> {
let tags = parse_config_tags(custom_headers.config_tags)?;
db_conn.transaction::<_, superposition::AppError, _>(|transaction_conn| {
let put_response = put(req, transaction_conn, true, &user, &state, &tenant)
let put_response = put(req, transaction_conn, true, &user, &tenant_config)
.map_err(|err: superposition::AppError| {
log::info!("context put failed with error: {:?}", err);
err
Expand All @@ -365,11 +363,10 @@ fn override_helper(
conn: &mut PooledConnection<ConnectionManager<PgConnection>>,
already_under_txn: bool,
user: &User,
state: &Data<AppState>,
tenant: Tenant,
tenant_config: &TenantConfig,
) -> superposition::Result<PutResp> {
use contexts::dsl::contexts;
let new_ctx = create_ctx_from_put_req(req, conn, user, state, &tenant)?;
let new_ctx = create_ctx_from_put_req(req, conn, user, &tenant_config)?;
if already_under_txn {
diesel::sql_query("SAVEPOINT insert_ctx_savepoint").execute(conn)?;
}
Expand Down Expand Up @@ -397,12 +394,12 @@ async fn update_override_handler(
req: Json<PutReq>,
mut db_conn: DbConnection,
user: User,
tenant: Tenant,
tenant_config: TenantConfig,
) -> superposition::Result<HttpResponse> {
let tags = parse_config_tags(custom_headers.config_tags)?;
db_conn.transaction::<_, superposition::AppError, _>(|transaction_conn| {
let override_resp =
override_helper(req, transaction_conn, true, &user, &state, tenant).map_err(
override_helper(req, transaction_conn, true, &user, &tenant_config).map_err(
|err: superposition::AppError| {
log::info!("context put failed with error: {:?}", err);
err
Expand All @@ -425,8 +422,7 @@ fn r#move(
conn: &mut PooledConnection<ConnectionManager<PgConnection>>,
already_under_txn: bool,
user: &User,
state: &Data<AppState>,
tenant: &Tenant,
tenant_config: &TenantConfig,
) -> superposition::Result<PutResp> {
use contexts::dsl;
let req = req.into_inner();
Expand All @@ -441,8 +437,7 @@ fn r#move(
)?;
validate_condition_with_mandatory_dimensions(
&req.context.into_inner(),
&state.mandatory_dimensions,
tenant,
&tenant_config.mandatory_dimensions,
)?;

if priority == 0 {
Expand Down Expand Up @@ -519,7 +514,7 @@ async fn move_handler(
req: Json<MoveReq>,
mut db_conn: DbConnection,
user: User,
tenant: Tenant,
tenant_config: TenantConfig,
) -> superposition::Result<HttpResponse> {
let tags = parse_config_tags(custom_headers.config_tags)?;
db_conn.transaction::<_, superposition::AppError, _>(|transaction_conn| {
Expand All @@ -529,8 +524,7 @@ async fn move_handler(
transaction_conn,
true,
&user,
&state,
&tenant,
&tenant_config,
)
.map_err(|err| {
log::info!("move api failed with error: {:?}", err);
Expand Down Expand Up @@ -669,7 +663,7 @@ async fn bulk_operations(
reqs: Json<Vec<ContextAction>>,
db_conn: DbConnection,
user: User,
tenant: Tenant,
tenant_config: TenantConfig,
) -> superposition::Result<HttpResponse> {
use contexts::dsl::contexts;
let DbConnection(mut conn) = db_conn;
Expand All @@ -680,18 +674,15 @@ async fn bulk_operations(
for action in reqs.into_inner().into_iter() {
match action {
ContextAction::Put(put_req) => {
let put_resp = put(
Json(put_req),
transaction_conn,
true,
&user,
&state,
&tenant,
)
.map_err(|err| {
log::error!("Failed at insert into contexts due to {:?}", err);
err
})?;
let put_resp =
put(Json(put_req), transaction_conn, true, &user, &tenant_config)
.map_err(|err| {
log::error!(
"Failed at insert into contexts due to {:?}",
err
);
err
})?;
response.push(ContextBulkResponse::Put(put_resp));
}
ContextAction::Delete(ctx_id) => {
Expand Down Expand Up @@ -725,8 +716,7 @@ async fn bulk_operations(
transaction_conn,
true,
&user,
&state,
&tenant,
&tenant_config,
)
.map_err(|err| {
log::error!("Failed at moving context reponse due to {:?}", err);
Expand Down
Loading

0 comments on commit 99c5707

Please sign in to comment.