Skip to content

Commit

Permalink
Extract owner and description for looker dashboards (#943)
Browse files Browse the repository at this point in the history
* Extract system contact & description

* Bump version

* Update model version

* Bump version
  • Loading branch information
elic-eon authored Aug 7, 2024
1 parent 62ce241 commit afe1642
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 16 deletions.
47 changes: 45 additions & 2 deletions metaphor/looker/extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from metaphor.looker.folder import FolderMap, FolderMetadata, build_directories
from metaphor.looker.lookml_parser import ModelMap, fullname, parse_project
from metaphor.models.metadata_change_event import (
AssetPlatform,
AssetStructure,
Chart,
ChartType,
Expand All @@ -32,6 +33,9 @@
HierarchyLogicalID,
HierarchyType,
SourceInfo,
SystemContact,
SystemContacts,
SystemDescription,
VirtualViewType,
)

Expand Down Expand Up @@ -106,8 +110,9 @@ async def extract(self) -> Collection[ENTITY_TYPES]:
)

folder_map = self._fetch_folders()
user_map = self._fetch_users()

dashboards = self._fetch_dashboards(model_map, folder_map)
dashboards = self._fetch_dashboards(model_map, folder_map, user_map)

entities: List[ENTITY_TYPES] = []
entities.extend(dashboards)
Expand All @@ -129,8 +134,20 @@ def _fetch_folders(self) -> FolderMap:

return folder_map

def _fetch_users(self) -> Dict[str, str]:
user_map: Dict[str, str] = {}
users = self._sdk.all_users()
json_dump_to_debug_file(users, "all_users.json")

for user in users:
if user.email is None or user.id is None:
continue
user_map[user.id] = user.email

return user_map

def _fetch_dashboards(
self, model_map: ModelMap, folder_map: FolderMap
self, model_map: ModelMap, folder_map: FolderMap, user_map: Dict[str, str]
) -> List[Dashboard]:
dashboards: List[Dashboard] = []

Expand All @@ -142,6 +159,9 @@ def _fetch_dashboards(

try:
dashboard = self._sdk.dashboard(dashboard_id=basic_dashboard.id)
json_dump_to_debug_file(
dashboard, f"{basic_dashboard.id}_dashboard.json"
)
except Exception as error:
logger.error(f"Failed to fetch dashboard {basic_dashboard.id}: {error}")
continue
Expand Down Expand Up @@ -188,6 +208,20 @@ def _fetch_dashboards(

assert dashboard.id is not None

owner_email = user_map.get(dashboard.user_id or "")
system_contacts = (
SystemContacts(
contacts=[
SystemContact(
email=owner_email,
system_contact_source=AssetPlatform.LOOKER,
)
]
)
if owner_email
else None
)

dashboards.append(
Dashboard(
logical_id=DashboardLogicalID(
Expand All @@ -206,6 +240,15 @@ def _fetch_dashboards(
if dashboard.folder and dashboard.folder.id
else None
),
system_contacts=system_contacts,
system_description=(
SystemDescription(
description=dashboard.description,
platform=AssetPlatform.LOOKER,
)
if dashboard.description
else None
),
)
)

Expand Down
4 changes: 2 additions & 2 deletions metaphor/tableau/extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from metaphor.common.logger import get_logger, json_dump_to_debug_file
from metaphor.models.crawler_run_metadata import Platform
from metaphor.models.metadata_change_event import (
AssetPlatform,
AssetStructure,
Chart,
Dashboard,
Expand All @@ -36,7 +37,6 @@
SourceInfo,
SystemContact,
SystemContacts,
SystemContactSource,
SystemTag,
SystemTags,
SystemTagSource,
Expand Down Expand Up @@ -229,7 +229,7 @@ def _get_system_contacts(

system_contact = SystemContact(
email=self._users[user_id].email,
system_contact_source=SystemContactSource.TABLEAU,
system_contact_source=AssetPlatform.TABLEAU,
)
return SystemContacts(contacts=[system_contact])

Expand Down
6 changes: 3 additions & 3 deletions metaphor/unity_catalog/extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from metaphor.common.utils import to_utc_datetime_from_timestamp
from metaphor.models.crawler_run_metadata import Platform
from metaphor.models.metadata_change_event import (
AssetPlatform,
DataPlatform,
Dataset,
DatasetLogicalID,
Expand All @@ -39,7 +40,6 @@
SQLSchema,
SystemContact,
SystemContacts,
SystemContactSource,
SystemTag,
SystemTags,
SystemTagSource,
Expand Down Expand Up @@ -366,7 +366,7 @@ def _init_dataset(self, table_info: TableInfo) -> Dataset:
contacts=[
SystemContact(
email=owner,
system_contact_source=SystemContactSource.UNITY_CATALOG,
system_contact_source=AssetPlatform.UNITY_CATALOG,
)
]
)
Expand Down Expand Up @@ -751,7 +751,7 @@ def _init_volume(self, volume: VolumeInfo):
contacts=[
SystemContact(
email=volume.owner,
system_contact_source=SystemContactSource.UNITY_CATALOG,
system_contact_source=AssetPlatform.UNITY_CATALOG,
)
]
)
Expand Down
11 changes: 6 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "metaphor-connectors"
version = "0.14.71"
version = "0.14.72"
license = "Apache-2.0"
description = "A collection of Python-based 'connectors' that extract metadata from various sources to ingest into the Metaphor app."
authors = ["Metaphor <[email protected]>"]
Expand Down Expand Up @@ -42,7 +42,7 @@ llama-index-readers-confluence = { version = "^0.1.4", optional = true }
llama-index-readers-notion = { version = "^0.1.6", optional = true }
looker-sdk = { version = "^24.2.0", optional = true }
lxml = { version = "~=5.0.0", optional = true }
metaphor-models = "0.37.2"
metaphor-models = "0.38.0"
more-itertools = { version = "^10.1.0", optional = true }
msal = { version = "^1.28.0", optional = true }
msgraph-beta-sdk = { version = "~1.4.0", optional = true }
Expand Down
16 changes: 16 additions & 0 deletions tests/looker/expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
"2"
],
"name": "first"
},
"systemDescription": {
"description": "first dashboard",
"platform": "LOOKER"
}
},
{
Expand Down Expand Up @@ -59,6 +63,18 @@
"2"
],
"name": "old version dashboard"
},
"systemContacts": {
"contacts": [
{
"email": "[email protected]",
"systemContactSource": "LOOKER"
}
]
},
"systemDescription": {
"description": "foo",
"platform": "LOOKER"
}
}
]
16 changes: 16 additions & 0 deletions tests/looker/expected_alternative.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
"2"
],
"name": "first"
},
"systemDescription": {
"description": "first dashboard",
"platform": "LOOKER"
}
},
{
Expand Down Expand Up @@ -59,6 +63,18 @@
"2"
],
"name": "old version dashboard"
},
"systemContacts": {
"contacts": [
{
"email": "[email protected]",
"systemContactSource": "LOOKER"
}
]
},
"systemDescription": {
"description": "foo",
"platform": "LOOKER"
}
}
]
9 changes: 7 additions & 2 deletions tests/looker/test_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def create_extractor(config: LookerRunConfig):
),
Dashboard(
id="4",
user_id="1",
title="old version dashboard",
description="foo",
preferred_viewer=None,
Expand Down Expand Up @@ -139,12 +140,16 @@ def create_extractor(config: LookerRunConfig):
"4": FolderMetadata(id="4", name="personal descendant", parent_id="3"),
}

dashboards = create_extractor(config)._fetch_dashboards(models, folders)
users = {
"1": "[email protected]",
}

dashboards = create_extractor(config)._fetch_dashboards(models, folders, users)

events = [EventUtil.trim_event(e) for e in dashboards]
assert events == load_json(f"{test_root_dir}/looker/expected.json")

config.alternative_base_url = "http://dev.test"
dashboards = create_extractor(config)._fetch_dashboards(models, folders)
dashboards = create_extractor(config)._fetch_dashboards(models, folders, users)
events = [EventUtil.trim_event(e) for e in dashboards]
assert events == load_json(f"{test_root_dir}/looker/expected_alternative.json")

0 comments on commit afe1642

Please sign in to comment.