From ddc18705ef1ca663cc7d628e8703ab05157607da Mon Sep 17 00:00:00 2001 From: janmatzek Date: Thu, 4 Sep 2025 13:12:26 +0200 Subject: [PATCH 1/2] docs(gooddata-pipelines): public documentation --- CONTRIBUTING.md | 2 + docs/content/en/latest/pipelines-overview.md | 58 +++++ docs/content/en/latest/pipelines/_index.md | 6 + .../latest/pipelines/provisioning/_index.md | 91 +++++++ .../pipelines/provisioning/user_groups.md | 177 +++++++++++++ .../en/latest/pipelines/provisioning/users.md | 200 +++++++++++++++ .../provisioning/workspace-permissions.md | 191 ++++++++++++++ .../pipelines/provisioning/workspaces.md | 233 ++++++++++++++++++ 8 files changed, 958 insertions(+) create mode 100644 docs/content/en/latest/pipelines-overview.md create mode 100644 docs/content/en/latest/pipelines/_index.md create mode 100644 docs/content/en/latest/pipelines/provisioning/_index.md create mode 100644 docs/content/en/latest/pipelines/provisioning/user_groups.md create mode 100644 docs/content/en/latest/pipelines/provisioning/users.md create mode 100644 docs/content/en/latest/pipelines/provisioning/workspace-permissions.md create mode 100644 docs/content/en/latest/pipelines/provisioning/workspaces.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6a3e6f193..e366b4814 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,6 +60,8 @@ The project documentation is done in hugo. To contribute: 2. Run `make new-docs` +3. Open [http://localhost:1313/latest/](http://localhost:1313/latest/) in your browser to see the preview. + The documentation is deployed using manually triggered GitHub workflows. One logical change is done in one commit. diff --git a/docs/content/en/latest/pipelines-overview.md b/docs/content/en/latest/pipelines-overview.md new file mode 100644 index 000000000..48e84c470 --- /dev/null +++ b/docs/content/en/latest/pipelines-overview.md @@ -0,0 +1,58 @@ +--- +title: "Pipelines Overview" +linkTitle: "Pipelines Overview" +weight: 14 +--- + +GoodData Pipelines contains tools for automating GoodData lifecycle management. Built on top of [GoodData Python SDK](https://www.gooddata.com/docs/python-sdk/latest/), it enables you to programmatically provision and manage workspaces, users, user groups, and their permissions. + +For further information, refer to the PIPELINES section in the left navigation menu. + +## Installation + +Run the following command to install the ``gooddata-pipelines`` package on your system: + +```bash +pip install gooddata-pipelines +``` + +### Requirements + +- Python 3.10 or newer +- GoodData.CN or GoodData Cloud + +## Examples + +Here is an introductory example of how to manage GoodData resources using GoodData Pipelines: + +### Provision Child Workspaces +```python +from gooddata_pipelines import WorkspaceFullLoad, WorkspaceProvisioner + +# GoodData.CN host URI (e.g., "http://localhost:3000") +host = "http://localhost:3000" + +# GoodData.CN user token +token = "some_user_token" + +# Initialize the provisioner +provisioner = WorkspaceProvisioner.create(host=host, token=token) + +# Gather the definitions of the workspaces you want to create +raw_data: list[dict] = [ + { + "parent_id": "demo_parent_workspace", + "workspace_id": "sales_team_workspace", + "workspace_name": "Sales Team Workspace", + "workspace_data_filter_id": "region_filter", + "workspace_data_filter_values": ["north_america"], + }, +] + +# Validate the data +validated_data = [WorkspaceFullLoad(**item) for item in raw_data] + +# Run the provisioning +provisioner.full_load(validated_data) + +``` diff --git a/docs/content/en/latest/pipelines/_index.md b/docs/content/en/latest/pipelines/_index.md new file mode 100644 index 000000000..3c7dd3374 --- /dev/null +++ b/docs/content/en/latest/pipelines/_index.md @@ -0,0 +1,6 @@ +--- +title: "GOODDATA PIPELINES" +linkTitle: "GOODDATA PIPELINES" +weight: 60 +navigationLabel: true +--- diff --git a/docs/content/en/latest/pipelines/provisioning/_index.md b/docs/content/en/latest/pipelines/provisioning/_index.md new file mode 100644 index 000000000..9429ab271 --- /dev/null +++ b/docs/content/en/latest/pipelines/provisioning/_index.md @@ -0,0 +1,91 @@ +--- +title: "Provisioning" +linkTitle: "Provisioning" +weight: 1 +no_list: true +--- + +Programmatically manage and provision resources in your GoodData environment. + +## Supported Resources + +Resources you can provision using GoodData Pipelines: + +- [Workspaces](workspaces/) +- [Users](users/) +- [User Groups](user_groups/) +- [Workspace Permissions](workspace-permissions/) + + +## Workflow Types + +There are two types of provisioning supported by GoodData Pipelines: + +- [Full load](#full-load) +- [Incremental load](#incremental-load) + +The provisioning types employ different algorithms and expect different structures of input data. For details about the expected inputs, check out the documentation page for each individual resource. + +### Full Load + +Full load provisioning aims to fully synchronize the state of your GoodData instance with the provided input. This workflow will create new resources and update existing ones based on the input. Any resources existing on GoodData Cloud not included in the input will be deleted. + +{{% alert color="warning" title="Full loads are destrucitve"%}} +Full load provisioning will delete any existing resources not included in your input data. Test in non-production environment. +{{% /alert %}} + +### Incremental Load + +During incremental provisioning, the algorithm will only interact with resources specified in the input. During the incremental load, the input data expects an extra parameter: `is_active`. Resources with `True` value will be updated. On the other hand, by setting it to `False`, you can mark resources for deletion. Any other resources already existing in GoodData will not be altered. + +### Workflow Comparison + +| **Aspect** | **Full Load** | **Incremental Load** | +|------------|---------------|----------------------| +| **Scope** | Synchronizes entire state | Only specified resources | +| **Deletion** | Deletes unspecified resources | Only deletes resources marked `is_active: False` | +| **Use Case** | Complete environment setup | Targeted updates | + +## Usage + +Regardless of workflow type or resource being provisioned, the typical usage follows these steps: + +1. Initialize the provisioner + +1. Validate your data using an input model + +1. Run the selected provisioning method (`.full_load()` or `.incremental_load()`) with your validated data + + +Check the [resource pages](#supported-resources) for detailed instructions and examples of workflow implementations. + +## Logs + +By default, the provisioners operate silently. To monitor progress and troubleshoot issues, you can subscribe to the emitted logs using the `.subscribe()` method on the `logger` property of the provisioner instance. + +```python +# Import and set up your logger +import logging + +# Import the provisioner +from gooddata_pipelines import WorkspaceProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# In this example, we will use Python standard logging library. +# However, you can use any logger conforming to the LoggerLike protocol +# defined in gooddata_pipelines.logger.logger +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +# Initialize the provisioner +provisioner = WorkspaceProvisioner.create(host=host, token=token) + +# Subscribe to the logging service +provisioner.logger.subscribe(logger) + +# Continue with the provisioning +... +``` diff --git a/docs/content/en/latest/pipelines/provisioning/user_groups.md b/docs/content/en/latest/pipelines/provisioning/user_groups.md new file mode 100644 index 000000000..16dd862ad --- /dev/null +++ b/docs/content/en/latest/pipelines/provisioning/user_groups.md @@ -0,0 +1,177 @@ +--- +title: "User Groups" +linkTitle: "User Group" +weight: 3 +--- + +User group provisioning allows you to create, update, or delete user groups. + +User groups enable you to organize users and manage permissions at scale by assigning permissions to groups rather than individual users. + +You can provision user groups using full or incremental load methods. Each of these methods requires a specific input type. + +## Usage + +Start by importing and initializing the UserGroupProvisioner. + +```python + +from gooddata_pipelines import UserGroupProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = UserGroupProvisioner.create(host=host, token=token) + +``` + + +Then validate your data using an input model corresponding to the provisioned resource and selected workflow type, i.e., `UserGroupFullLoad` if you intend to run the provisioning in full load mode, or `UserGroupIncrementalLoad` if you want to provision incrementally. + +The models expect the following fields: +- **user_group_id**: ID of the user group. +- **user_group_name**: Name of the user group. +- **parent_user_groups**: A list of parent user group IDs. +- _**is_active**:_ Deletion flag. Present only in the IncrementalLoad models. + +{{% alert color="info" title="Note on IDs"%}} +Each ID can only contain allowed characters. See [Workspace Object Identification](https://www.gooddata.com/docs/cloud/create-workspaces/objects-identification/) to learn more about object identifiers. +{{% /alert %}} + +Use the appropriate model to validate your data: + +```python +# Add the model to the imports +from gooddata_pipelines import UserGroupFullLoad, UserGroupProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = UserGroupProvisioner.create(host=host, token=token) + +# Load your data +raw_data = [ + { + "user_group_id": "user_group_1", + "user_group_name": "User Group 1", + "parent_user_groups": [], + }, +] + +# Validate the data +validated_data = [ + UserGroupFullLoad( + user_group_id=item["user_group_id"], + user_group_name=item["user_group_name"], + parent_user_groups=item["parent_user_groups"], + ) + for item in raw_data +] + +``` + +Now with the provisioner initialized and your data validated, you can run the provisioner: + +```python +# Import, initialize, validate... +... + +# Run the provisioning method +provisioner.full_load(validated_data) + +``` + +## Examples + +Here are full examples of a full load and incremental load user group provisioning workflows: + +### Full Load + +```python +import logging + +from gooddata_pipelines import UserGroupFullLoad, UserGroupProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = UserGroupProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data = [ + { + "user_group_id": "user_group_1", + "user_group_name": "User Group 1", + "parent_user_groups": [], + }, +] + +# Validate the data +validated_data = [ + UserGroupFullLoad( + user_group_id=item["user_group_id"], + user_group_name=item["user_group_name"], + parent_user_groups=item["parent_user_groups"], + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.full_load(validated_data) + +``` + + +### Incremental Load + +```python +import logging + +from gooddata_pipelines import UserGroupIncrementalLoad, UserGroupProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = UserGroupProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data = [ + { + "user_group_id": "user_group_1", + "user_group_name": "User Group 1", + "parent_user_groups": [], + "is_active": True, + }, +] + +# Validate the data +validated_data = [ + UserGroupIncrementalLoad( + user_group_id=item["user_group_id"], + user_group_name=item["user_group_name"], + parent_user_groups=item["parent_user_groups"], + is_active=item["is_active"], + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.incremental_load(validated_data) + +``` diff --git a/docs/content/en/latest/pipelines/provisioning/users.md b/docs/content/en/latest/pipelines/provisioning/users.md new file mode 100644 index 000000000..e192db9fe --- /dev/null +++ b/docs/content/en/latest/pipelines/provisioning/users.md @@ -0,0 +1,200 @@ +--- +title: "Users" +linkTitle: "Users" +weight: 2 +--- + + +User provisioning allows you to create, update, or delete user profiles in your GoodData environment. + +You can provision users using full or incremental load methods. Each of these methods requires a specific input type. + +## Usage + +Start by importing and initializing the UserProvisioner. + +```python + +from gooddata_pipelines import UserProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = UserProvisioner.create(host=host, token=token) + +``` + + +Then validate your data using an input model corresponding to the provisioned resource and selected workflow type, i.e., `UserFullLoad` if you intend to run the provisioning in full load mode, or `UserIncrementalLoad` if you want to provision incrementally. + +The models expect the following fields: + +- **user_id**: User ID. +- **firstname**: First name of the user. +- **lastname**: Last name of the user. +- **email**: Email of the user. +- **auth_id**: Authorization ID associated with the user. +- **user_groups**: List of user group IDs that the user should belong to. +- _**is_active**:_ Deletion flag. Present only in the IncrementalLoad models. + +{{% alert color="info" title="Note on IDs"%}} +Each ID can only contain allowed characters. See [Workspace Object Identification](https://www.gooddata.com/docs/cloud/create-workspaces/objects-identification/) to learn more about object identifiers. +{{% /alert %}} + +Use the appropriate model to validate your data: + +```python +# Add the model to the imports +from gooddata_pipelines import UserIncrementalLoad, UserProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = UserProvisioner.create(host=host, token=token) + +# Load your data +raw_data = [ + { + "user_id": "user_id_1", + "firstname": "Example", + "lastname": "User", + "email": "example.user@gooddata.com", + "auth_id": "", + "user_groups": ["user_group_1", "user_group_2"], + "is_active": True, + }, +] + +# Validate the data +validated_data = [ + UserIncrementalLoad( + user_id=item["user_id"], + firstname=item["firstname"], + lastname=item["lastname"], + email=item["email"], + auth_id=item["auth_id"], + user_groups=item["user_groups"], + is_active=item["is_active"], + ) + for item in raw_data +] + +``` + +Now with the provisioner initialized and your data validated, you can run the provisioner: + +```python +# Import, initialize, validate... +... + +# Run the provisioning method +provisioner.incremental_load(validated_data) + +``` + +## Examples + +Here are full examples of a full load and incremental load user provisioning workflows: + +### Full Load + +```python +import logging + +from gooddata_pipelines import UserFullLoad, UserProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = UserProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data = [ + { + "user_id": "user_id_1", + "firstname": "Example", + "lastname": "User", + "email": "example.user@gooddata.com", + "auth_id": "", + "user_groups": ["user_group_1", "user_group_2"], + }, +] + +# Validate the data +validated_data = [ + UserFullLoad( + user_id=item["user_id"], + firstname=item["firstname"], + lastname=item["lastname"], + email=item["email"], + auth_id=item["auth_id"], + user_groups=item["user_groups"], + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.full_load(validated_data) + +``` + + +### Incremental Load + +```python +import logging + +from gooddata_pipelines import UserIncrementalLoad, UserProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = UserProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data = [ + { + "user_id": "user_id_1", + "firstname": "Example", + "lastname": "User", + "email": "example.user@gooddata.com", + "auth_id": "", + "user_groups": ["user_group_1", "user_group_2"], + "is_active": True, + }, +] + +# Validate the data +validated_data = [ + UserIncrementalLoad( + user_id=item["user_id"], + firstname=item["firstname"], + lastname=item["lastname"], + email=item["email"], + auth_id=item["auth_id"], + user_groups=item["user_groups"], + is_active=item["is_active"], + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.incremental_load(validated_data) + +``` diff --git a/docs/content/en/latest/pipelines/provisioning/workspace-permissions.md b/docs/content/en/latest/pipelines/provisioning/workspace-permissions.md new file mode 100644 index 000000000..79aa455b3 --- /dev/null +++ b/docs/content/en/latest/pipelines/provisioning/workspace-permissions.md @@ -0,0 +1,191 @@ +--- +title: "Workspace Permissions" +linkTitle: "Workspace Permissions" +weight: 4 +--- + +Workspace permission provisioning allows you to create, update, or delete user permissions. See [Manage Workspace Permissions](https://www.gooddata.com/docs/cloud/manage-organization/manage-permissions/set-permissions-for-workspace/) to learn more about workspace permissions in GoodData Cloud. + +You can provision workspace permissions using full or incremental load methods. Each of these methods requires a specific input type. + +## Usage + +Start by importing and initializing the PermissionProvisioner. + +```python + +from gooddata_pipelines import PermissionProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = PermissionProvisioner.create(host=host, token=token) + +``` + + +Then validate your data using an input model corresponding to the provisioned resource and selected workflow type, i.e., `PermissionFullLoad` if you intend to run the provisioning in full load mode, or `PermissionIncrementalLoad` if you want to provision incrementally. + +The models expect the following fields: +- **permission**: Permission you want to grant, e.g., `VIEW`, `ANALYZE`, `MANAGE`. +- **workspace_id**: ID of the workspace the permission will be applied to. +- **entity_id**: ID of the entity (user or user group) which will receive the permission. +- **entity_type**: Type of the entity receiving the permission - either `user` or `userGroup`. +- _**is_active**:_ Deletion flag. Present only in the IncrementalLoad models. + +{{% alert color="info" title="Note on IDs"%}} +Each ID can only contain allowed characters. See [Workspace Object Identification](https://www.gooddata.com/docs/cloud/create-workspaces/objects-identification/) to learn more about object identifiers. +{{% /alert %}} + +Use the appropriate model to validate your data: + +```python +# Add the model and the EntityType enumeration to the imports +from gooddata_pipelines import ( + EntityType, + PermissionIncrementalLoad, + PermissionProvisioner, +) + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = PermissionProvisioner.create(host=host, token=token) + +raw_data = [ + { + "permission": "VIEW", + "workspace_id": "workspace_id_1", + "entity_id": "user_1", + "entity_type": "user", + "is_active": True, + } +] + +# Validate the data +validated_data = [ + PermissionIncrementalLoad( + permission=item["permission"], + workspace_id=item["workspace_id"], + entity_id=item["entity_id"], + entity_type=EntityType(item["entity_type"]), + is_active=item["is_active"], + ) + for item in raw_data +] + +``` + +Now with the provisioner initialized and your data validated, you can run the provisioner: + +```python +# Import, initialize, validate... +... + +# Run the provisioning method +provisioner.incremental_load(validated_data) + +``` + +## Examples + +Here are full examples of a full load and incremental load permission provisioning workflows: + +### Full Load + +```python +import logging + +from gooddata_pipelines import EntityType, PermissionFullLoad, PermissionProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = PermissionProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data = [ + { + "permission": "VIEW", + "workspace_id": "workspace_id_1", + "entity_id": "user_1", + "entity_type": "user", + } +] + +# Validate the data +validated_data = [ + PermissionFullLoad( + permission=item["permission"], + workspace_id=item["workspace_id"], + entity_id=item["entity_id"], + entity_type=EntityType(item["entity_type"]), + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.full_load(validated_data) + +``` + + +### Incremental Load + +```python +import logging + +from gooddata_pipelines import ( + EntityType, + PermissionIncrementalLoad, + PermissionProvisioner, +) + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = PermissionProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data = [ + { + "permission": "VIEW", + "workspace_id": "workspace_id_1", + "entity_id": "user_1", + "entity_type": "user", + "is_active": True, + } +] + +# Validate the data +validated_data = [ + PermissionIncrementalLoad( + permission=item["permission"], + workspace_id=item["workspace_id"], + entity_id=item["entity_id"], + entity_type=EntityType(item["entity_type"]), + is_active=item["is_active"], + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.incremental_load(validated_data) + +``` diff --git a/docs/content/en/latest/pipelines/provisioning/workspaces.md b/docs/content/en/latest/pipelines/provisioning/workspaces.md new file mode 100644 index 000000000..a3da061a9 --- /dev/null +++ b/docs/content/en/latest/pipelines/provisioning/workspaces.md @@ -0,0 +1,233 @@ +--- +title: "Workspaces" +linkTitle: "Workspaces" +weight: 1 +--- + +Workspace provisioning allows you to create, update or delete child workspaces. + +{{% alert color="info" title="Multitenancy in GoodData"%}} +See [Multitenancy: One Platform, Many Customers](https://www.gooddata.com/resources/multitenancy-product-tour/) to learn more about how to leverage child workspaces in GoodData. +{{% /alert %}} + +You can provision child workspaces using full or incremental load methods. Each of these methods requires a specific input type. + + +## Usage + +Start by importing and initializing the WorkspaceProvisioner. + +```python + +from gooddata_pipelines import WorkspaceProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = WorkspaceProvisioner.create(host=host, token=token) + +``` + + +Then validate your data using an input model corresponding to the provisioned resource and selected workflow type, i.e., `WorkspaceFullLoad` if you intend to run the provisioning in full load mode, or `WorkspaceIncrementalLoad` if you want to provision incrementally. + +The models expect the following fields: + +- **parent_id**: ID of the parent workspace. +- **workspace_id**: ID of the child workspace. +- **workspace_name**: Name of the child workspace. +- **workspace_data_filter_id**: ID of the workspace data filter to apply (must exist on parent workspace). +- **workspace_data_filter_values**: List of filter values that determine which data this workspace can access. +- _**is_active**:_ Deletion flag. Present only in the IncrementalLoad models. + +{{% alert color="info" title="Note on IDs"%}} +Each ID can only contain allowed characters. See [Workspace Object Identification](https://www.gooddata.com/docs/cloud/create-workspaces/objects-identification/) to learn more about object identifiers. +{{% /alert %}} + +Use the appropriate model to validate your data: + +```python +# Add the model to the imports +from gooddata_pipelines import WorkspaceFullLoad, WorkspaceProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner with GoodData credentials +provisioner = WorkspaceProvisioner.create(host=host, token=token) + +# Load your data +raw_data = [ + { + "parent_id": "parent_workspace_id", + "workspace_id": "workspace_id_1", + "workspace_name": "Workspace 1", + "workspace_data_filter_id": "data_filter_id", + "workspace_data_filter_values": ["workspace_data_filter_value_1"], + }, +] + +# Validate the data +validated_data = [ + WorkspaceFullLoad( + parent_id=item["parent_id"], + workspace_id=item["workspace_id"], + workspace_name=item["workspace_name"], + workspace_data_filter_id=item["workspace_data_filter_id"], + workspace_data_filter_values=item["workspace_data_filter_values"], + ) + for item in raw_data +] + + +``` + +Now with the provisioner initialized and your data validated, you can run the provisioner: + +```python +# Import, initialize, validate... +... + +# Run the provisioning method +provisioner.full_load(validated_data) +``` + + +## Workspace Data Filters + +If you want to apply Workspace Data Filters to a child workspace, the filter must be set up on the parent workspace before you run the provisioning. + +{{% alert color="info" title="Workspace Data Filters"%}} +See [Set Up Data Filters in Workspaces](https://www.gooddata.com/docs/cloud/workspaces/workspace-data-filters/) to learn how workspace data filters work in GoodData. +{{% /alert %}} + +## Examples + +Here are full examples of a full load and incremental load workspace provisioning workflows: + +### Full Load + +```python +import logging + +from gooddata_pipelines import WorkspaceFullLoad, WorkspaceProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = WorkspaceProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data: list[dict] = [ + { + "parent_id": "parent_workspace_id", + "workspace_id": "workspace_id_1", + "workspace_name": "Workspace 1", + "workspace_data_filter_id": "data_filter_id", + "workspace_data_filter_values": ["workspace_data_filter_value_1"], + }, + { + "parent_id": "parent_workspace_id", + "workspace_id": "workspace_id_2", + "workspace_name": "Workspace 2", + "workspace_data_filter_id": "data_filter_id", + "workspace_data_filter_values": ["workspace_data_filter_value_2"], + }, + { + "parent_id": "parent_workspace_id", + "workspace_id": "child_workspace_id_1", + "workspace_name": "Workspace 3", + "workspace_data_filter_id": "data_filter_id", + "workspace_data_filter_values": ["workspace_data_filter_value_3"], + }, +] + +# Validate the data +validated_data = [ + WorkspaceFullLoad( + parent_id=item["parent_id"], + workspace_id=item["workspace_id"], + workspace_name=item["workspace_name"], + workspace_data_filter_id=item["workspace_data_filter_id"], + workspace_data_filter_values=item["workspace_data_filter_values"], + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.full_load(validated_data) + +``` + +### Incremental Load + +```python +import logging + +from gooddata_pipelines import WorkspaceIncrementalLoad, WorkspaceProvisioner + +host = "http://localhost:3000" +token = "some_user_token" + +# Initialize the provisioner +provisioner = WorkspaceProvisioner.create(host=host, token=token) + +# Optional: set up logging and subscribe to logs emitted by the provisioner +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +provisioner.logger.subscribe(logger) + +# Prepare your data +raw_data: list[dict] = [ + { + "parent_id": "parent_workspace_id", + "workspace_id": "workspace_id_1", + "workspace_name": "Workspace 1", + "workspace_data_filter_id": "data_filter_id", + "workspace_data_filter_values": ["workspace_data_filter_value_1"], + "is_active": True, + }, + { + "parent_id": "parent_workspace_id", + "workspace_id": "workspace_id_2", + "workspace_name": "Workspace 2", + "workspace_data_filter_id": "data_filter_id", + "workspace_data_filter_values": ["workspace_data_filter_value_2"], + "is_active": True, + }, + { + "parent_id": "parent_workspace_id", + "workspace_id": "child_workspace_id_1", + "workspace_name": "Workspace 3", + "workspace_data_filter_id": "data_filter_id", + "workspace_data_filter_values": ["workspace_data_filter_value_3"], + "is_active": False, # This will mark the workspace for deletion + }, +] + +# Validate the data +validated_data = [ + WorkspaceIncrementalLoad( + parent_id=item["parent_id"], + workspace_id=item["workspace_id"], + workspace_name=item["workspace_name"], + workspace_data_filter_id=item["workspace_data_filter_id"], + workspace_data_filter_values=item["workspace_data_filter_values"], + is_active=item["is_active"], + ) + for item in raw_data +] + +# Run the provisioning with the validated data +provisioner.incremental_load(validated_data) + +``` From 5df217ce16385ef6cd87f06b0ff4041568a3f4a5 Mon Sep 17 00:00:00 2001 From: janmatzek Date: Thu, 11 Sep 2025 15:20:45 +0200 Subject: [PATCH 2/2] chore(docs): increase API Reference weight --- docs/content/en/latest/api-reference/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/en/latest/api-reference/_index.md b/docs/content/en/latest/api-reference/_index.md index 6ed6280e4..df77a072a 100644 --- a/docs/content/en/latest/api-reference/_index.md +++ b/docs/content/en/latest/api-reference/_index.md @@ -1,7 +1,7 @@ --- title: "API Reference" linkTitle: "API Reference" -weight: 60 +weight: 99 navigationLabel: true ---