Create a Multitenant Environment
This tutorial will guide you through the process of creating a multitenant environment.
The multitenant environment allows you to share the same logical data model and metrics, visualizations, and dashboards (so-called “analytical model”) among multiple consumers while keeping their data private (each consumer can access only their data).
For example, your company has multiple clients (tenants) who use your application. You want to build a business analytics experience where all your tenants will use the same metrics, visualizations, and dashboards, but each tenant will see only their own data (the data that is relevant to and is associated with a specific tenant). You can also use a multitenant environment inside the company to present different data to different company departments while the analytical model is the same across the company.
A multitenant environment is implemented through a workspace hierarchy and data filters.
- A workspace hierarchy is a tree structure describing relations between parent workspaces and their child workspaces. A child workspace inherits entities from its parent workspace. Any change in the parent workspace is immediately propagated to the child workspace. At the same time, the child workspace can have its own entities in addition to those inherited from the parent workspace. For more information about the workspace hierarchy, see Build a Workspace Hierarchy.
- Data filters allow you to limit the data available in child workspaces. By setting a data filter, you can define what subset of the data from a parent workspace will be available in its child workspaces. For more information about the data filters, see Set Up Data Filters in Workspaces.
- Alternatively, you can define different data sources for each tenant. See the Unique Data Sources for Tenants section for details.
The following picture shows how a visualization in a child workspace looks like comparing to the same visualization in the parent workspace when the data filter that filters the data in the child workspace by region is applied:
To create a multitenant hierarchy, do the following:
Build a Workspace Hierarchy
You are going to create a simple workspace hierarchy where the demo
workspace is a parent workspace with two child workspaces.
graph LR demo --> West demo --> NorthEast
For more information about the workspace hierarchy, see Build a Workspace Hierarchy.
Note
If you create the demo workspace in your browser, a random hash ID is generated for it. You can find the ID in your browser URL, when you open the demo workspace. Use this ID instead of “demo_workspace_id” in the following examples.
Steps:
Create a child workspace called
West
under thedemo
workspace.UIAPIOpen the Workspaces tab, click the demo workspace, then click Create child workspace.
For details, see Build a Workspace Hierarchy.
BashPowerShell 7curl http://localhost:3000/api/v1/entities/workspaces \ -H "Content-Type: application/vnd.gooddata.api+json" \ -H "Accept: application/vnd.gooddata.api+json" \ -H "Authorization: Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz" \ -X POST \ -d '{ "data": { "attributes": { "description": "My child workspace.", "name": "West" }, "id": "myWestWorkspaceId", "type": "workspace", "relationships": { "parent": { "data": { "id": "demo_workspace_id", "type": "workspace" } } } } }' | jq .
Invoke-RestMethod -Method Post -Uri 'http://localhost:3000/api/v1/entities/workspaces' ` -ContentType 'application/vnd.gooddata.api+json' ` -H @{ 'Accept' = 'application/vnd.gooddata.api+json' 'Authorization' = 'Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz' } ` -Body '{ "data": { "attributes": { "description": "My child workspace.", "name": "West" }, "id": "myWestWorkspaceId", "type": "workspace", "relationships": { "parent": { "data": { "id": "demo_workspace_id", "type": "workspace" } } } } }' | ConvertTo-Json
To confirm that the workspace has been created, the server returns the following response: ```json { "data": { "id": "myWestWorkspaceId", "type": "workspace", "attributes": { "description": "My child workspace.", "name": "West" } }, "links": { "self": "http://localhost:3000/api/v1/entities/workspaces/West" } } ```
Create a child workspace called
NorthEast
under thedemo
workspace.Go to the home page and check that the two workspaces,
West
andNorthEast
, have appeared in the list of workspaces.(Optional) Open the
West
workspace and check that it contains the dashboard and visualization that you created in thedemo
workspace.
How to Create Multiple Child Workspaces at Once
The procedure described earlier is helpful when you need to create just a few child workspaces, and you can create them one by one. If you need to create many workspaces (for example, dozens or hundreds), you can update the workspace declarative API layout that describes all your workspaces.
Steps:
Download the complete declarative document, and save it to your machine (
/tmp/ws-layout
is used as an example location in the following code samples):BashPowerShell 7curl http://localhost:3000/api/v1/layout/workspaces \ -H "Authorization: Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz" \ | jq > /tmp/ws-layout.json
Invoke-RestMethod -Uri 'http://localhost:3000/api/v1/layout/workspaces' ` -H @{ 'Authorization' = 'Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz' } ` -OutFile $env:TEMP\ws-layout.json
The downloaded document contains the definition of the
demo
workspace with all of the objects that it holds as well as the definitions of theWest
andNorthEast
workspaces, which are empty.Add the definition of another child workspace to the document. To do so, add the following JSON object to the top-level
workspaces
array:{ "id": "myWestWorkspaceId", "model": { "analytics": { "analyticalDashboards": [], "filterContexts": [], "metrics": [], "visualizationObjects": [] }, "ldm": { "datasets": [], "dateInstances": [] } }, "name": "Midwest", "parent": { "id": "demo_workspace_id", "type": "workspace" }, "settings": [ { "id": "timezone", "content": { "value": "Europe/Prague" } } ] }
Add as many child workspaces as you need by adding more JSON objects with a different name and ID for each workspace.
Upload the updated declarative document back to the server.
BashPowerShell 7curl http://localhost:3000/api/v1/layout/workspaces \ -H "Authorization: Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz" \ -H "Content-Type: application/json" \ -X PUT -d @/tmp/ws-layout.json
Invoke-RestMethod -Method Put -Uri 'http://localhost:3000/api/v1/layout/workspaces' ` -ContentType 'application/json' ` -H @{ 'Authorization' = 'Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz' } ` -InFile $env:TEMP\ws-layout.json
Go to the home page and check that the workspaces that you added have appeared in the list of workspaces.
Set Up Data Filters
You now have the workspace hierarchy where the child workspaces inherit the analytical model from the parent workspace, demo
. They also share the same data source and the data stored in this data source.
You are going to set up a data filter to limit the data available in the child workspaces by region, which is determined by the values of the Region
attribute. When the data filter is applied:
- The
West
workspace should be able to access only the data that is related to the West region. - The
NorthEast
workspace should not be able to access any region-related data.
Note
The name of the column used for filtering contains the prefix wdf__
.
No labels are generated into the logical data model (LDM) for columns with this prefix.
You can find wdf__region
column only in order_lines
table represented by Order lines
dataset in the LDM.
With the demo model there are two cases when data is filtered:
- If an entity (label, fact) from
Order lines
is used - Path between used entities goes through
Order lines
dataset- e.g. count of
Campaign id
byState
implies the following path:Campaigns
-Order Lines
-Customers
- e.g. count of
For more information about the data filters, see Set Up Data Filters in Workspaces.
Steps:
Create a JSON document that describes the data filter. The column that should be used for filtering the data is
wdf__region
(it contains the values of theRegion
attribute).To limit the data in the
West
workspace to the West region, assign theWest
filter value to the workspace.To restrict all the region-related data in the
West
workspace (child ofdemo
workspace), do not assign any filter value to it. Because the definition of data filters is tied to the parent workspaces, no data will be available in the child workspace if a filter value is not explicitly assigned to the child (hereWest
) workspace in the filter definition.
{ "workspaceDataFilters": [ { "id": "region", "title": "Customer Region", "columnName": "wdf__region", "workspace": { "id": "demo_workspace_id", "type": "workspace" }, "workspaceDataFilterSettings": [ { "id": "region_west", "title": "Region West", "filterValues": [ "West" ], "workspace": { "id": "west_workspace_id", "type": "workspace" } } ] } ] }
Upload the JSON document to the server.
BashPowerShell 7curl http://localhost:3000/api/v1/layout/workspaceDataFilters \ -H "Authorization: Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz" \ -H "Content-Type:application/json" \ -X PUT -d @/tmp/ws-filter.json
Invoke-RestMethod -Method Put -Uri 'http://localhost:3000/api/v1/layout/workspaceDataFilters' ` -ContentType 'application/json' ` -H @{ 'Authorization' = 'Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz' } ` -InFile $env:TEMP\ws-filter.json
The data filter is applied.
With this data filter in place, when opening or creating a visualization where the Region
attribute is used, you can expect the following:
- In the
demo
workspace, the visualization shows data for all the regions. - In the
West
workspace, the visualization shows only the data related to the Western region.
Note
Customers
dataset contains Region
attribute (label) mapped to region
column (no wdf__
prefix!).
This enables users in the parent demo
workspace slicing by this attribute (they can see data from all regions).
This does not make sense in child workspaces, which can see only data from single region.
To overcome this issue, you can create a view and expose the column region
twice - as region
and as wdf__region
.
Users will still be able to slice Region
attribute in all workspaces, but users in child workspaces will see data only from single region.
- In the
NorthEast
workspace, the visualization shows no region-related data (no values from theRegion
attribute are available).
Unique Data Sources for Tenants
You can set up distinct data sources for child workspaces, which can be useful when your source data is structured on a tenant-specific basis, such as utilizing different database schemas or databases for each tenant. This approach aids in managing strictly separated data, adding an extra dimension of data management alongside workspace data filters.
The child workspace must use the same logical data model as its parent workspace and must be the last node in the hierarchy, meaning it cannot have its own child workspaces. Creating a new child workspace subordinated to a child workspace with a unique data source will cause the new workspace to inherit the settings, including the data source, from the root (top-level parent) workspace.
In setting up data sources for child workspaces, it’s required to include the dataSource
in the definition. The dataSource
ID may be the same as the parent workspace’s. Yet, you’re allowed to define a unique schemaPath
for the child workspace, enabling customized data management under the same data source structure. Without a specified schemaPath
, the child workspace defaults to inheriting its settings, including the data source, from the root (top-level parent) workspace.
To define the data source, you must possess the organization.MANAGE
permission.
Limitations
The data source definition for a dataset must align with that of the workspace, including any inherited definitions or those of inherited datasets.
There may be incompatibility issues with SQL dialects when changing the data source type across the hierarchy. For example, the Median function is supported by Postgres but not by Apache Arrow.
Child workspaces must be configured to reflect the functionality of the parent data source accurately.
SQL datasets will not function with differing data sources.
The current design for different data sources per tenant does not support Multiple Data Sources in an LDM. Attempting to access a data source other than the primary one will result in a 400 error message like this:
{
"title": "Bad Request",
"status": 400,
"detail": "A result cache error has occurred during the calculation of the result",
"resultId": "83ae5f2dd53444cfda2abaa65a8faba724218591",
"reason": "No data source in Calcique compute request",
"traceId": "461808709beade2b37d06303c73250c3"
}
Configuration:
To set a data source for a child workspace, make a PUT
request to the /api/v1/entities/workspaces/{workspaceId}
API. Use the following parameters in your child workspace definition:
{
"data": {
"id": "childWorkspace",
"type": "workspace",
"attributes": {
"dataSource": {
"id": "workspaceDatasource",
"schemaPath": [
"schemaName"
]
}
},
"relationships": {
"parent": {
"data": {
"id": "parentWorkspace",
"type": "workspace"
}
}
}
}
}
The Declarative API can set up multiple workspaces in one request. To set a data source for a child workspace, make a PUT
request to the /api/v1/layout/workspaces/{workspaceId}
API with the following parameters in your child workspace definition:
{
"workspaces": [
{
"id": "subws3",
"name": "sub-work-space3",
"parent": {
"id": "ws1",
"type": "workspace"
},
"dataSource": {
"id": "workspaceDatasource",
"schemaPath": [
"schema"
]
}
}
],
"workspaceDataFilters": []
}