mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-18 05:57:17 +00:00
Chore: Tableau Improvements (#21620)
* Chore: Tableau Improvements * Added apiVersion * linting * Addressed Comments
This commit is contained in:
parent
407eb24baf
commit
161b4a8b2a
@ -13,7 +13,7 @@ Wrapper module of TableauServerConnection client
|
||||
"""
|
||||
import math
|
||||
import traceback
|
||||
from typing import Callable, Dict, List, Optional, Tuple, Union
|
||||
from typing import Callable, Dict, Iterable, List, Optional, Tuple, Union
|
||||
|
||||
import validators
|
||||
from cached_property import cached_property
|
||||
@ -77,16 +77,18 @@ class TableauClient:
|
||||
self,
|
||||
tableau_server_auth: Union[PersonalAccessTokenAuth, TableauAuth],
|
||||
config,
|
||||
verify_ssl,
|
||||
verify_ssl: Union[bool, str],
|
||||
pagination_limit: int,
|
||||
):
|
||||
self.tableau_server = Server(str(config.hostPort), use_server_version=True)
|
||||
if config.apiVersion:
|
||||
self.tableau_server.version = config.apiVersion
|
||||
self.tableau_server.add_http_options({"verify": verify_ssl})
|
||||
self.tableau_server.auth.sign_in(tableau_server_auth)
|
||||
self.config = config
|
||||
self.pagination_limit = pagination_limit
|
||||
self.custom_sql_table_queries: Dict[str, List[str]] = {}
|
||||
self.usage_metrics: Dict[str, int] = {}
|
||||
self.owner_cache: Dict[str, TableauOwner] = {}
|
||||
|
||||
@cached_property
|
||||
def server_info(self) -> Callable:
|
||||
@ -101,9 +103,15 @@ class TableauClient:
|
||||
|
||||
def get_tableau_owner(self, owner_id: str) -> Optional[TableauOwner]:
|
||||
try:
|
||||
if owner_id in self.owner_cache:
|
||||
return self.owner_cache[owner_id]
|
||||
owner = self.tableau_server.users.get_by_id(owner_id) if owner_id else None
|
||||
if owner and owner.email:
|
||||
return TableauOwner(id=owner.id, name=owner.name, email=owner.email)
|
||||
owner_obj = TableauOwner(
|
||||
id=owner.id, name=owner.name, email=owner.email
|
||||
)
|
||||
self.owner_cache[owner_id] = owner_obj
|
||||
return owner_obj
|
||||
except Exception as err:
|
||||
logger.debug(f"Failed to fetch owner details for ID {owner_id}: {str(err)}")
|
||||
return None
|
||||
@ -130,21 +138,20 @@ class TableauClient:
|
||||
)
|
||||
view_count += view.total_views
|
||||
except AttributeError as e:
|
||||
logger.warning(
|
||||
logger.debug(
|
||||
f"Failed to process view due to missing attribute: {str(e)}"
|
||||
)
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to process view: {str(e)}")
|
||||
logger.debug(f"Failed to process view: {str(e)}")
|
||||
continue
|
||||
|
||||
return charts, view_count
|
||||
|
||||
def get_workbooks(self) -> List[TableauDashboard]:
|
||||
def get_workbooks(self) -> Iterable[TableauDashboard]:
|
||||
"""
|
||||
Fetch all tableau workbooks
|
||||
"""
|
||||
workbooks: Optional[List[TableauDashboard]] = []
|
||||
self.cache_custom_sql_tables()
|
||||
for workbook in Pager(self.tableau_server.workbooks):
|
||||
try:
|
||||
@ -152,22 +159,20 @@ class TableauClient:
|
||||
charts, user_views = self.get_workbook_charts_and_user_count(
|
||||
workbook.views
|
||||
)
|
||||
workbooks.append(
|
||||
TableauDashboard(
|
||||
id=workbook.id,
|
||||
name=workbook.name,
|
||||
project=TableauBaseModel(
|
||||
id=workbook.project_id, name=workbook.project_name
|
||||
),
|
||||
description=workbook.description,
|
||||
owner=self.get_tableau_owner(workbook.owner_id),
|
||||
tags=workbook.tags,
|
||||
webpageUrl=workbook.webpage_url,
|
||||
charts=charts,
|
||||
dataModels=self.get_datasources(dashboard_id=workbook.id),
|
||||
user_views=user_views,
|
||||
)
|
||||
workbook = TableauDashboard(
|
||||
id=workbook.id,
|
||||
name=workbook.name,
|
||||
project=TableauBaseModel(
|
||||
id=workbook.project_id, name=workbook.project_name
|
||||
),
|
||||
owner=self.get_tableau_owner(workbook.owner_id),
|
||||
description=workbook.description,
|
||||
tags=workbook.tags,
|
||||
webpageUrl=workbook.webpage_url,
|
||||
charts=charts,
|
||||
user_views=user_views,
|
||||
)
|
||||
yield workbook
|
||||
except AttributeError as err:
|
||||
logger.warning(
|
||||
f"Failed to process workbook due to missing attribute: {str(err)}"
|
||||
@ -176,7 +181,6 @@ class TableauClient:
|
||||
except Exception as err:
|
||||
logger.warning(f"Failed to process workbook: {str(err)}")
|
||||
continue
|
||||
return workbooks
|
||||
|
||||
def test_get_workbooks(self):
|
||||
for workbook in Pager(self.tableau_server.workbooks):
|
||||
|
@ -13,7 +13,7 @@
|
||||
Source connection handler
|
||||
"""
|
||||
import traceback
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any, Dict, Optional, Union
|
||||
|
||||
import tableauserverclient as TSC
|
||||
|
||||
@ -38,7 +38,6 @@ from metadata.ingestion.ometa.ometa_api import OpenMetadata
|
||||
from metadata.ingestion.source.dashboard.tableau.client import TableauClient
|
||||
from metadata.utils.constants import THREE_MIN
|
||||
from metadata.utils.logger import ingestion_logger
|
||||
from metadata.utils.ssl_registry import get_verify_ssl_fn
|
||||
|
||||
logger = ingestion_logger()
|
||||
|
||||
@ -48,12 +47,12 @@ def get_connection(connection: TableauConnection) -> TableauClient:
|
||||
Create connection
|
||||
"""
|
||||
tableau_server_auth = build_server_config(connection)
|
||||
get_verify_ssl = get_verify_ssl_fn(connection.verifySSL)
|
||||
verify_ssl = set_verify_ssl(connection)
|
||||
try:
|
||||
return TableauClient(
|
||||
tableau_server_auth=tableau_server_auth,
|
||||
config=connection,
|
||||
verify_ssl=get_verify_ssl(connection.sslConfig),
|
||||
verify_ssl=verify_ssl,
|
||||
pagination_limit=connection.paginationLimit,
|
||||
)
|
||||
except Exception as exc:
|
||||
@ -63,6 +62,21 @@ def get_connection(connection: TableauConnection) -> TableauClient:
|
||||
)
|
||||
|
||||
|
||||
def set_verify_ssl(connection: TableauConnection) -> Union[bool, str]:
|
||||
"""
|
||||
Set verify ssl based on connection configuration
|
||||
ref: https://tableau.github.io/server-client-python/docs/sign-in-out#handling-ssl-certificates-for-tableau-server
|
||||
"""
|
||||
if connection.verifySSL.value == "validate":
|
||||
if connection.sslConfig.root.caCertificate:
|
||||
return connection.sslConfig.root.caCertificate.get_secret_value()
|
||||
if connection.sslConfig.root.sslCertificate:
|
||||
return connection.sslConfig.root.sslCertificate.get_secret_value()
|
||||
if connection.verifySSL.value == "ignore":
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
def test_connection(
|
||||
metadata: OpenMetadata,
|
||||
client: TableauClient,
|
||||
|
@ -127,8 +127,8 @@ class TableauSource(DashboardServiceSource):
|
||||
)
|
||||
return cls(config, metadata)
|
||||
|
||||
def get_dashboards_list(self) -> Optional[List[TableauDashboard]]:
|
||||
return self.client.get_workbooks()
|
||||
def get_dashboards_list(self) -> Iterable[TableauDashboard]:
|
||||
yield from self.client.get_workbooks()
|
||||
|
||||
def get_dashboard_name(self, dashboard: TableauDashboard) -> str:
|
||||
return dashboard.name
|
||||
@ -137,6 +137,7 @@ class TableauSource(DashboardServiceSource):
|
||||
"""
|
||||
Get Dashboard Details including the dashboard charts and datamodels
|
||||
"""
|
||||
dashboard.dataModels = self.client.get_datasources(dashboard.id)
|
||||
return dashboard
|
||||
|
||||
def get_owner_ref(
|
||||
|
@ -52,6 +52,12 @@
|
||||
"type": "integer",
|
||||
"default": 10
|
||||
},
|
||||
"apiVersion": {
|
||||
"title": "API Version",
|
||||
"description": "Tableau API version. If not provided, the version will be used from the tableau server.",
|
||||
"type": "string",
|
||||
"default": null
|
||||
},
|
||||
"verifySSL": {
|
||||
"$ref": "../../../../security/ssl/verifySSLConfig.json#/definitions/verifySSL",
|
||||
"default": "no-ssl"
|
||||
|
@ -14,6 +14,10 @@
|
||||
* Tableau Connection Config
|
||||
*/
|
||||
export interface TableauConnection {
|
||||
/**
|
||||
* Tableau API version. If not provided, the version will be used from the tableau server.
|
||||
*/
|
||||
apiVersion?: string;
|
||||
/**
|
||||
* Types of methods used to authenticate to the tableau instance
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user