Skip to content

Commit 7ab977f

Browse files
authored
feat(native): Cube.py - support orchestratorOptions/http/jwt (#7135)
1 parent 2cc754c commit 7ab977f

File tree

10 files changed

+59
-58
lines changed

10 files changed

+59
-58
lines changed

packages/cubejs-api-gateway/src/gateway.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2123,7 +2123,7 @@ class ApiGateway {
21232123
}
21242124

21252125
const jwk = await jwks.getJWKbyKid(
2126-
typeof options.jwkUrl === 'function' ? options.jwkUrl(decoded) : <string>options.jwkUrl,
2126+
typeof options.jwkUrl === 'function' ? await options.jwkUrl(decoded) : <string>options.jwkUrl,
21272127
decoded.header.kid
21282128
);
21292129
if (!jwk) {

packages/cubejs-api-gateway/src/types/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ interface JWTOptions {
2727
// JWK options
2828
jwkRetry?: number,
2929
jwkDefaultExpire?: number,
30-
jwkUrl?: ((payload: any) => string) | string,
30+
jwkUrl?: ((payload: any) => string | Promise<string>) | string,
3131
jwkRefetchWindow?: number,
3232

3333
// JWT options

packages/cubejs-backend-native/python/cube/src/conf/__init__.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class Configuration:
4040
cache_and_queue_driver: str
4141
allow_js_duplicate_props_in_schema: bool
4242
process_subscriptions_interval: int
43+
http: Dict
44+
jwt: Dict
4345
# Functions
4446
logger: Callable
4547
context_to_app_id: Union[str, Callable[[RequestContext], str]]
@@ -53,9 +55,10 @@ class Configuration:
5355
scheduled_refresh_contexts: Callable
5456
context_to_api_scopes: Callable
5557
repository_factory: Callable
56-
schema_version: Callable[[RequestContext], str]
57-
semantic_layer_sync: Callable
58-
pre_aggregations_schema: Callable[[RequestContext], str]
58+
schema_version: Union[str, Callable[[RequestContext], str]]
59+
semantic_layer_sync: Union[Dict, Callable[[], Dict]]
60+
pre_aggregations_schema: Union[Callable[[RequestContext], str]]
61+
orchestrator_options: Union[Dict, Callable[[RequestContext], Dict]]
5962

6063
def __init__(self):
6164
self.schema_path = None
@@ -67,6 +70,8 @@ def __init__(self):
6770
self.cache_and_queue_driver = None
6871
self.allow_js_duplicate_props_in_schema = None
6972
self.process_subscriptions_interval = None
73+
self.http = None
74+
self.jwt = None
7075
# Functions
7176
self.logger = None
7277
self.context_to_app_id = None
@@ -84,6 +89,7 @@ def __init__(self):
8489
self.schema_version = None
8590
self.semantic_layer_sync = None
8691
self.pre_aggregations_schema = None
92+
self.orchestrator_options = None
8793

8894
def set_schema_path(self, schema_path: str):
8995
self.schema_path = schema_path
@@ -148,15 +154,18 @@ def set_scheduled_refresh_contexts(self, scheduled_refresh_contexts: Callable):
148154
def set_repository_factory(self, repository_factory: Callable):
149155
self.repository_factory = repository_factory
150156

151-
def set_schema_version(self, schema_version: Callable[[RequestContext], str]):
157+
def set_schema_version(self, schema_version: Union[str, Callable[[RequestContext], str]]):
152158
self.schema_version = schema_version
153159

154-
def set_semantic_layer_sync(self, semantic_layer_sync: Callable):
160+
def set_semantic_layer_sync(self, semantic_layer_sync: Union[Dict, Callable[[], Dict]]):
155161
self.semantic_layer_sync = semantic_layer_sync
156162

157-
def set_pre_aggregations_schema(self, pre_aggregations_schema: Callable[[RequestContext], str]):
163+
def set_pre_aggregations_schema(self, pre_aggregations_schema: Union[str, Callable[[RequestContext], str]]):
158164
self.pre_aggregations_schema = pre_aggregations_schema
159165

166+
def set_orchestrator_options(self, orchestrator_options: Union[Dict, Callable[[RequestContext], Dict]]):
167+
self.orchestrator_options = orchestrator_options
168+
160169

161170
settings = Configuration()
162171

packages/cubejs-backend-native/src/python/cross.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ impl CLRepr {
286286
}
287287

288288
Self::Tuple(r)
289+
} else if v.get_type().is_subclass_of::<PyFunction>()? {
290+
let fun: Py<PyFunction> = v.downcast::<PyFunction>()?.into();
291+
292+
Self::PyFunction(fun)
289293
} else {
290294
return Err(PyErr::new::<PyTypeError, _>(format!(
291295
"Unable to represent {} type as CLR from Python",

packages/cubejs-backend-native/src/python/cube_config.rs

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use convert_case::{Case, Casing};
22
use neon::prelude::*;
3-
use pyo3::exceptions::PyTypeError;
4-
use pyo3::types::PyFunction;
5-
use pyo3::{Py, PyAny, PyErr, PyResult};
3+
use pyo3::{PyAny, PyResult};
64

75
use crate::python::cross::{CLRepr, CLReprObject};
86

@@ -28,56 +26,34 @@ impl CubeConfigPy {
2826
"cache_and_queue_driver",
2927
"allow_js_duplicate_props_in_schema",
3028
"process_subscriptions_interval",
29+
"http",
30+
"jwt",
3131
]
3232
}
3333

3434
pub fn apply_dynamic_functions(&mut self, config_module: &PyAny) -> PyResult<()> {
35-
self.function_attr(config_module, "logger")?;
36-
self.function_attr(config_module, "context_to_app_id")?;
37-
self.function_attr(config_module, "context_to_orchestrator_id")?;
38-
self.function_attr(config_module, "driver_factory")?;
39-
self.function_attr(config_module, "db_type")?;
40-
self.function_attr(config_module, "check_auth")?;
41-
self.function_attr(config_module, "check_sql_auth")?;
42-
self.function_attr(config_module, "can_switch_sql_user")?;
43-
self.function_attr(config_module, "query_rewrite")?;
44-
self.function_attr(config_module, "extend_context")?;
45-
self.function_attr(config_module, "scheduled_refresh_contexts")?;
46-
self.function_attr(config_module, "context_to_api_scopes")?;
47-
self.function_attr(config_module, "repository_factory")?;
48-
self.function_attr(config_module, "semantic_layer_sync")?;
49-
self.function_attr(config_module, "schema_version")?;
50-
self.function_attr(config_module, "pre_aggregations_schema")?;
35+
self.attr(config_module, "logger")?;
36+
self.attr(config_module, "context_to_app_id")?;
37+
self.attr(config_module, "context_to_orchestrator_id")?;
38+
self.attr(config_module, "driver_factory")?;
39+
self.attr(config_module, "db_type")?;
40+
self.attr(config_module, "check_auth")?;
41+
self.attr(config_module, "check_sql_auth")?;
42+
self.attr(config_module, "can_switch_sql_user")?;
43+
self.attr(config_module, "query_rewrite")?;
44+
self.attr(config_module, "extend_context")?;
45+
self.attr(config_module, "scheduled_refresh_contexts")?;
46+
self.attr(config_module, "context_to_api_scopes")?;
47+
self.attr(config_module, "repository_factory")?;
48+
self.attr(config_module, "semantic_layer_sync")?;
49+
self.attr(config_module, "schema_version")?;
50+
self.attr(config_module, "pre_aggregations_schema")?;
51+
self.attr(config_module, "orchestrator_options")?;
5152

5253
Ok(())
5354
}
5455

55-
pub fn function_attr<'a>(
56-
&mut self,
57-
config_module: &'a PyAny,
58-
key: &str,
59-
) -> PyResult<Option<Py<PyFunction>>> {
60-
let v = config_module.getattr(&*key)?;
61-
if !v.is_none() {
62-
if v.get_type().is_subclass_of::<PyFunction>()? {
63-
let cb = v.downcast::<PyFunction>()?;
64-
let py: Py<PyFunction> = cb.into();
65-
66-
let value = CLRepr::PyFunction(py);
67-
self.properties.insert(key.to_case(Case::Camel), value);
68-
} else {
69-
return Err(PyErr::new::<PyTypeError, _>(format!(
70-
"Unsupported configuration type: {} for key: {}, must be a lambda",
71-
v.get_type(),
72-
key
73-
)));
74-
}
75-
}
76-
77-
Ok(None)
78-
}
79-
80-
pub fn static_attr(&mut self, config_module: &PyAny, key: &str) -> PyResult<()> {
56+
pub fn attr(&mut self, config_module: &PyAny, key: &str) -> PyResult<()> {
8157
let v = config_module.getattr(&*key)?;
8258
if !v.is_none() {
8359
let value = CLRepr::from_python_ref(v)?;

packages/cubejs-backend-native/src/python/entry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn python_load_config(mut cx: FunctionContext) -> JsResult<JsPromise> {
3737
let mut cube_conf = CubeConfigPy::new();
3838

3939
for attr_name in cube_conf.get_static_attrs() {
40-
cube_conf.static_attr(settings_py, attr_name)?;
40+
cube_conf.attr(settings_py, attr_name)?;
4141
}
4242

4343
cube_conf.apply_dynamic_functions(settings_py)?;

packages/cubejs-server-core/src/core/optionsValidate.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ const jwtOptions = Joi.object().strict(true).keys({
2929
claimsNamespace: Joi.string(),
3030
});
3131

32+
const corsOptions = Joi.object().strict(true).keys({
33+
origin: Joi.any(),
34+
methods: Joi.any(),
35+
allowedHeaders: Joi.any(),
36+
exposedHeaders: Joi.any(),
37+
credentials: Joi.bool(),
38+
maxAge: Joi.number(),
39+
preflightContinue: Joi.bool(),
40+
optionsSuccessStatus: Joi.bool(),
41+
});
42+
3243
const dbTypes = Joi.alternatives().try(
3344
Joi.string().valid(...Object.keys(DriverDependencies)),
3445
Joi.func()
@@ -38,8 +49,8 @@ const schemaOptions = Joi.object().keys({
3849
// server CreateOptions
3950
initApp: Joi.func(),
4051
webSockets: Joi.boolean(),
41-
http: Joi.object().keys({
42-
cors: Joi.object(),
52+
http: Joi.object().strict(true).keys({
53+
cors: corsOptions,
4354
}),
4455
gracefulShutdown: Joi.number().min(0).integer(),
4556
// Additional from WebSocketServerOptions

packages/cubejs-server-core/src/core/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ export class CubejsServerCore {
559559
const orchestratorOptions =
560560
this.optsHandler.getOrchestratorInitializedOptions(
561561
context,
562-
this.orchestratorOptions(context) || {},
562+
(await this.orchestratorOptions(context)) || {},
563563
);
564564

565565
const orchestratorApi = this.createOrchestratorApi(

packages/cubejs-server-core/src/core/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export type DatabaseType =
125125
export type ContextToAppIdFn = (context: RequestContext) => string | Promise<string>;
126126
export type ContextToOrchestratorIdFn = (context: RequestContext) => string | Promise<string>;
127127

128-
export type OrchestratorOptionsFn = (context: RequestContext) => OrchestratorOptions;
128+
export type OrchestratorOptionsFn = (context: RequestContext) => OrchestratorOptions | Promise<OrchestratorOptions>;
129129

130130
export type PreAggregationsSchemaFn = (context: RequestContext) => string | Promise<string>;
131131

packages/cubejs-server/src/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export class CubejsServer {
6161
protected readonly status: ServerStatusHandler = new ServerStatusHandler();
6262

6363
public constructor(config: CreateOptions = {}, systemOptions?: SystemOptions) {
64+
console.log(config);
6465
this.config = {
6566
...config,
6667
webSockets: config.webSockets || getEnv('webSockets'),

0 commit comments

Comments
 (0)