cube-js / cube

📊 Cube — The Semantic Layer for Building Data Applications
https://cube.dev
Other
17.92k stars 1.78k forks source link

Issue with Schema Generation w/ Multi-Tenancy Configuration #8624

Open christopher-leigh opened 2 months ago

christopher-leigh commented 2 months ago

Describe the bug We are experiencing an issue in the Cube data model generation with our multi-tenancy configuration. We are able to query the API successfully and run queries within the Playground successfully. However when we attempt to generate new Cube configuration files via the "Tables" feature in the "Data Model" tab, we receive the following error in the UI:

Error while loading DB schema
Error: Python error: TypeError: 'NoneType' object is not subscriptable Traceback (most recent call last): File "cube.py", line 26, in driver_factory "database": ctx["securityContext"]["tenant_db"],

We are connecting to Snowflake and querying different databases depending on the security context provided.

Our hunch is that the security context we've provided in the "Playground" page is not carrying over to the request made in the "Data Model" tab. We've found that if we remove our driver_factory config and supply a CUBEJS_DB_NAME environment variable we no longer experience this issue.

Here is our cube.py for reference:

from tenants import create_security_context

from cube import config

@config("context_to_app_id")
def context_to_app_id(ctx: dict) -> dict:
    return (
        f"{ctx['securityContext']['tenant_db']}_{ctx['securityContext']['environment']}"
    )

@config("context_to_orchestrator_id")
def context_to_orchestrator_id(ctx: dict) -> str:
    return (
        f"{ctx['securityContext']['tenant_db']}_{ctx['securityContext']['environment']}"
    )

@config("driver_factory")
def driver_factory(ctx: dict) -> None:
    return {
        "type": "snowflake",
        "database": ctx["securityContext"]["tenant_db"],
    }

@config("pre_aggregations_schema")
def pre_aggregations_schema(ctx: dict) -> str:
    return f"pre_aggregations_{ctx['securityContext']['tenant_db']}_{ctx['securityContext']['environment']}"

@config("scheduled_refresh_contexts")
def scheduled_refresh_contexts() -> list[object]:
    return create_security_context()

To Reproduce Steps to reproduce the behavior: 1) Go to Playground (http://localhost:4000) 2) Enter security context (queries run successfully) 3) Go to "Data Model" page 4) Click "Tables"

Expected behavior Cube should be able to generate the database object information and we should be able to select the tables and automatically generate Cube YAML.

Screenshots

image

Minimally reproducible Cube Schema In case your bug report is data modelling related please put your minimally reproducible Cube Schema here. You can use selects without tables in order to achieve that as follows.

cubes:
  - name: table_one
    sql_table: "\"DBT_{COMPILE_CONTEXT.securityContext.tenant_db}\".\"TABLE_ONE\""
    data_source: default

    joins:
      - name: other_table
        relationship: one_to_one
        sql: "{CUBE.user_id} = {other_table.user_id}"

    dimensions:
      - name: user_id
        sql: "{CUBE}.\"USER_ID\""
        type: string

    measures:
      - name: count
        type: count

    pre_aggregations:

Version: CUBE_VERSION=0.35

Additional context Add any other context about the problem here.

github-actions[bot] commented 2 months ago

If you are interested in working on this issue, please go ahead and provide PR for that. We'd be happy to review it and merge it. If this is the first time you are contributing a Pull Request to Cube, please check our contribution guidelines. You can also post any questions while contributing in the #contributors channel in the Cube Slack.

igorlukanin commented 2 months ago

Hi @christopher-leigh 👋

Thanks for reporting!

Our hunch is that the security context we've provided in the "Playground" page is not carrying over to the request made in the "Data Model" tab.

I think this is correct. Looks like the issue here is that the Data Model tab does not work with the security context in Playground—and it was never designed to.

As a workaround that you can use right now, you can provide the credentials statically, generate data models, and then merge them manually.

christopher-leigh commented 2 months ago

Thanks for the response @igorlukanin! That's helpful for us to know. We'll continue with that workaround for the time being.