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 --> NorthEastFor 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
Westunder thedemoworkspace.Open 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-JsonTo 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
NorthEastunder thedemoworkspace.Go to the home page and check that the two workspaces,
WestandNorthEast, have appeared in the list of workspaces.(Optional) Open the
Westworkspace and check that it contains the dashboard and visualization that you created in thedemoworkspace.
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-layoutis 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.jsonInvoke-RestMethod -Uri 'http://localhost:3000/api/v1/layout/workspaces' ` -H @{ 'Authorization' = 'Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz' } ` -OutFile $env:TEMP\ws-layout.jsonThe downloaded document contains the definition of the
demoworkspace with all of the objects that it holds as well as the definitions of theWestandNorthEastworkspaces, 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
workspacesarray:{ "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.jsonInvoke-RestMethod -Method Put -Uri 'http://localhost:3000/api/v1/layout/workspaces' ` -ContentType 'application/json' ` -H @{ 'Authorization' = 'Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz' } ` -InFile $env:TEMP\ws-layout.jsonGo 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
Westworkspace should be able to access only the data that is related to the West region. - The
NorthEastworkspace 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 linesis used - Path between used entities goes through
Order linesdataset- e.g. count of
Campaign idbyStateimplies 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 theRegionattribute).To limit the data in the
Westworkspace to the West region, assign theWestfilter value to the workspace.To restrict all the region-related data in the
Westworkspace (child ofdemoworkspace), 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.jsonInvoke-RestMethod -Method Put -Uri 'http://localhost:3000/api/v1/layout/workspaceDataFilters' ` -ContentType 'application/json' ` -H @{ 'Authorization' = 'Bearer YWRtaW46Ym9vdHN0cmFwOmFkbWluMTIz' } ` -InFile $env:TEMP\ws-filter.jsonThe 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
demoworkspace, the visualization shows data for all the regions. - In the
Westworkspace, 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
NorthEastworkspace, the visualization shows no region-related data (no values from theRegionattribute 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": []
}

