Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ingestion/tableau): introduce project_path_pattern #10855

Conversation

haeniya
Copy link
Contributor

@haeniya haeniya commented Jul 5, 2024

Description

We have the need to exclude certain projects and all their nested projects from the ingestion. Unfortunately, this is not possible with the current project_pattern as this currently allows a project to be ingested if the project name OR the project path is allowed by the pattern, see:

is_allowed: bool = self.config.project_pattern.allowed(
project.name
) or self.config.project_pattern.allowed(self._get_project_path(project))

For example, if you have a project structure as follows: Project1/Nested1/Test1, Project1/Nested1/Test2, Project1/Nested2/Test1 and you would like to deny "Nested1" and all its nested projects, we couldn't find a way to do this. Using a regex like ^.*Nested1.*$ in the deny section of project_pattern would still ingest the nested projects because the project name is allowed. And a project is allowed if either the name or the project path is allowed.

This PR introduces a new config property project_path_pattern that exclusively checks the project path of a project when deciding if a project is allowed to be ingested or not. This enables the mentioned use case to be configured.

The current implementation of project_pattern also seems to have some flaws that I would like to discuss with you (see comments).
Let me know what you think.

Many thanks.

Checklist

  • The PR conforms to DataHub's Contributing Guideline (particularly Commit Message Format)
  • Links to related issues (if applicable)
  • Tests for the changes have been added/updated (if applicable)
  • Docs related to the changes have been added/updated (if applicable). If a new feature has been added a Usage Guide has been added for the same.
  • For any breaking change/potential downtime/deprecation/big changes an entry has been made in Updating DataHub

Summary by CodeRabbit

  • New Features
    • Introduced the ability to filter Tableau projects based on their full path using project_path_pattern, supporting both allow and deny patterns via Regex.

Copy link
Contributor

coderabbitai bot commented Jul 5, 2024

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The TableauConfig class in tableau.py has been enhanced with a new project_path_pattern field enabling users to filter Tableau projects based on their complete path. The _is_allowed_project method has been updated to include these project path checks alongside existing project name checks.

Changes

File Change Summary
metadata-ingestion/src/datahub/...py Added project_path_pattern in TableauConfig and updated _is_allowed_project to use this field

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TableauConfig
    participant Tableau Project

    User->>TableauConfig: Configure project_path_pattern
    User->>TableauConfig: Call method to filter projects
    TableauConfig->>Tableau Project: Retrieve project path
    TableauConfig->>TableauConfig: Check if project_path matches pattern
    alt Project Path Allowed
        TableauConfig->>User: Project is allowed
    else Project Path Denied
        TableauConfig->>User: Project is denied
    end
Loading

Poem

In lines of code, a pattern set,
To catch the paths where projects get.
Filtering dreams in Tableau land,
With logic fine and code so grand.
A rabbit's joy for fields anew,
To keep the data crisp and true.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added ingestion PR or Issue related to the ingestion of metadata community-contribution PR or Issue raised by member(s) of DataHub Community labels Jul 5, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between ebe7b2d and 1b5cfb9.

Files selected for processing (1)
  • metadata-ingestion/src/datahub/ingestion/source/tableau.py (3 hunks)
Additional comments not posted (2)
metadata-ingestion/src/datahub/ingestion/source/tableau.py (2)

296-304: New field project_path_pattern added.

The new field project_path_pattern allows filtering Tableau projects based on their full path using allow and deny patterns. This provides more granular control over project ingestion, addressing the limitations of the existing project_pattern.


694-700: Modified method _is_allowed_project to include project_path_pattern.

The method _is_allowed_project now incorporates checks against the new project_path_pattern in addition to the existing project_pattern. This ensures that both the project name and the full project path are considered when determining if a project should be ingested.


for project in list_of_skip_projects:
if (
project.parent_id in self.tableau_project_registry
Copy link
Contributor Author

@haeniya haeniya Jul 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing something but from my understanding, this can never happen.
If we only add projects to list_of_skip_projects that are not allowed, there will never be a project in this list that is not denied as it is checked below.

When checking if a project is allowed, the following is executed downstream

if self._denied(string):
return False
and this also checks if it's denied.

What do you think? Am I missing something here?

EDIT: I checked this again because the failing tests indicate that this indeed does something. I think I know how it could work. The method _is_denied_project only checks the deny part of the pattern in the config and _is_allowed_project checks both the allowed part and the deny part of the pattern under the hood. So if for a project the path or the name is not allowed but not explicitly denied, this part here would still add it if the parent project was added (and extract_project_hierarchy was enabled). But I don't really understand the use case for this. Could someone shed some light on this? Why do we need extract_project_hierarchy?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might have been implemented based on user requests to include child projects by default unless explicitly denied. Could you please revert these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the thing, I think we always include child projects with or without the property extract_project_hierarchy. So I don't really understand why we need it. From what I understand, the only use case, where this property actually has an impact is the one I mentioned above:

So if for a project the path or the name is not allowed but not explicitly denied, this part here would still add it if the parent project was added (and extract_project_hierarchy was enabled).

I can revert the changes, but IMO we should have a further look at this part as it does things that are hard to understand, at least for me. Could be that as the code evolved over time, we don't even need it anymore.
Again, maybe I'm missing something and for some reason this makes total sense, but it could be worth checking again. @sid-acryl could you do that together with @hsheth2?

@@ -681,30 +691,16 @@ def form_path(project_id: str) -> List[str]:

def _is_allowed_project(self, project: TableauProject) -> bool:
# Either project name or project path should exist in allow
is_allowed: bool = self.config.project_pattern.allowed(
Copy link
Contributor Author

@haeniya haeniya Jul 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We encountered some issues with the current implementation. The problem is that both project paths and project names can be controlled with the same pattern.

For example, if you deny a nested project by its path e.g. "Project1/Nested1/Test (Catalog)" but allow all projects with "(Catalog)" in the name (by a regex). The denied project "Project1/Nested1/Test (Catalog)" would still be ingested as the project name is allowed. Or if we for example want to deny all projects with "(Sensitive)" in the path this can't be achieved because the names might be allowed.

Ideally, I think it would make sense to completely separate project_path_pattern and project_name_pattern to avoid these cases. But this would break backwards compatibility.

What do you think about this?

@haeniya haeniya changed the title feat(ingestion/tableau): introduce platform_path_pattern feat(ingestion/tableau): introduce project_path_pattern Jul 11, 2024
@hsheth2 hsheth2 requested a review from sid-acryl July 23, 2024 19:42

for project in list_of_skip_projects:
if (
project.parent_id in self.tableau_project_registry
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might have been implemented based on user requests to include child projects by default unless explicitly denied. Could you please revert these changes?

@@ -320,6 +320,16 @@ class TableauConfig(
"By default, all projects will be ingested.",
)

project_path_pattern: AllowDenyPattern = Field(
default=AllowDenyPattern.allow_all(),
description="Filter for specific Tableau projects by checking their full path. For example, use 'My Project/Nested Project' to ingest a nested project with name 'Nested Project'. "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please update the description as per below text:

"Filters Tableau projects by their full path. For instance, 'My Project/Nested Project' targets a specific nested project named 'Nested Project'."
" Unlike project_pattern, this field only checks the project path, not both the path and project name."
" This is useful when you need to exclude all nested projects under a particular project."
" You can allow or deny projects by specifying their path or a regular expression pattern."
" Deny patterns always override allow patterns."
" By default, all projects are ingested."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, changed it.

Copy link
Contributor

@sid-acryl sid-acryl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just minor change in description, otherwise looks ok.

):
logger.debug(f"Project {project.name} is added in project registry")
self.tableau_project_registry[project.id] = project
# We rely on automatic browse paths (v2) when creating containers. That's why we need to sort the projects here.
Copy link
Contributor Author

@haeniya haeniya Sep 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted the changes to include the extract_project_hierarchy part again, as discussed. However, I slightly refactored it so we do the sorting below at the very end for all the projects to ingest. Let me know if you see any problem with this.

Copy link
Contributor

@sid-acryl sid-acryl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@sid-acryl sid-acryl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fields project_pattern and project_path_pattern might cause confusion for users.
Please implement the following changes:

  • Mark project_pattern as deprecated and recommend using project_path_pattern going forward. refer _deprecate_projects = pydantic_field_deprecated("projects") in tableau config
  • Add validation to ensure project_pattern and project_path_pattern are mutually exclusive.

@haeniya
Copy link
Contributor Author

haeniya commented Sep 24, 2024

The fields project_pattern and project_path_pattern might cause confusion for users. Please implement the following changes:

  • Mark project_pattern as deprecated and recommend using project_path_pattern going forward. refer _deprecate_projects = pydantic_field_deprecated("projects") in tableau config
  • Add validation to ensure project_pattern and project_path_pattern are mutually exclusive.

I guess they both serve different purposes and that's why I wouldn't just deprecate project_pattern. As mentioned in one of my previous comments (#10855 (comment)) I think it would make sense to completely separate project_path_pattern and project_name_pattern to avoid these issues. But this would break backwards compatibility to current ingestions unfortunately. But if feels a bit strange to me that the project_pattern checks for both the path and the project name. What do you think?

@sid-acryl
Copy link
Contributor

The fields project_pattern and project_path_pattern might cause confusion for users. Please implement the following changes:

  • Mark project_pattern as deprecated and recommend using project_path_pattern going forward. refer _deprecate_projects = pydantic_field_deprecated("projects") in tableau config
  • Add validation to ensure project_pattern and project_path_pattern are mutually exclusive.

I guess they both serve different purposes and that's why I wouldn't just deprecate project_pattern. As mentioned in one of my previous comments (#10855 (comment)) I think it would make sense to completely separate project_path_pattern and project_name_pattern to avoid these issues. But this would break backwards compatibility to current ingestions unfortunately. But if feels a bit strange to me that the project_pattern checks for both the path and the project name. What do you think?

I preferred project-path based ingestion because of following reason:

  • project-path is inherently unique whereas project-name is not unique and it can lead to ambiguity when multiple projects have the same name
  • project-name losses the context about it location whereas project-path is context aware and allow us to retain the hierarchical structure and allows us to better organize and locate projects, especially in environments with complex project trees
  • As tableau instance is grows, the likelihood of having duplicate project names increases, leading to challenges in scaling metadata ingestion pipeline.

so better to have a one way of doing the things to avoid confusion later.

@haeniya
Copy link
Contributor Author

haeniya commented Sep 25, 2024

The fields project_pattern and project_path_pattern might cause confusion for users. Please implement the following changes:

  • Mark project_pattern as deprecated and recommend using project_path_pattern going forward. refer _deprecate_projects = pydantic_field_deprecated("projects") in tableau config
  • Add validation to ensure project_pattern and project_path_pattern are mutually exclusive.

I guess they both serve different purposes and that's why I wouldn't just deprecate project_pattern. As mentioned in one of my previous comments (#10855 (comment)) I think it would make sense to completely separate project_path_pattern and project_name_pattern to avoid these issues. But this would break backwards compatibility to current ingestions unfortunately. But if feels a bit strange to me that the project_pattern checks for both the path and the project name. What do you think?

I preferred project-path based ingestion because of following reason:

  • project-path is inherently unique whereas project-name is not unique and it can lead to ambiguity when multiple projects have the same name
  • project-name losses the context about it location whereas project-path is context aware and allow us to retain the hierarchical structure and allows us to better organize and locate projects, especially in environments with complex project trees
  • As tableau instance is grows, the likelihood of having duplicate project names increases, leading to challenges in scaling metadata ingestion pipeline.

so better to have a one way of doing the things to avoid confusion later.

You're right, since we can also use the new project_path_pattern to allow/deny specific projects we should be fine with just this property in the future. I'll try to implement the deprecation as you suggested.

logger.warning(
"project_pattern is not set but projects is set. projects is deprecated, please use "
"project_pattern instead."
"projects is deprecated, please use " "project_path_pattern instead."
)
logger.info("Initializing project_pattern from projects")
values["project_pattern"] = AllowDenyPattern(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sid-acryl I now deprecated project_pattern but I wanted to point out that for now this validation rule still initializes project_pattern when projects is set. Ideally, we would remove the old projects completely now but I tried it and it would require quite some refactoring in the tests.

@hsheth2 hsheth2 added the merge-pending-ci A PR that has passed review and should be merged once CI is green. label Sep 27, 2024
@hsheth2 hsheth2 merged commit 99bfcef into datahub-project:master Sep 27, 2024
92 of 93 checks passed
sleeperdeep pushed a commit to sleeperdeep/datahub that referenced this pull request Dec 17, 2024
…ect#10855)

Co-authored-by: Yanik Häni <Yanik.Haeni1@swisscom.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community-contribution PR or Issue raised by member(s) of DataHub Community ingestion PR or Issue related to the ingestion of metadata merge-pending-ci A PR that has passed review and should be merged once CI is green.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants