Skip to content

Commit

Permalink
fix(ingestion/metabase): Fetch Dashboards through Collections (#9631)
Browse files Browse the repository at this point in the history
Co-authored-by: Harshal Sheth <[email protected]>
  • Loading branch information
7onn and hsheth2 authored Jan 26, 2024
1 parent 69ff9c3 commit f7f0b14
Show file tree
Hide file tree
Showing 9 changed files with 901 additions and 345 deletions.
2 changes: 1 addition & 1 deletion metadata-ingestion/developing.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Also take a look at the guide to [adding a source](./adding-source.md).
### Requirements

1. Python 3.7+ must be installed in your host environment.
2. Java8 (gradle won't work with newer versions)
2. Java 17 (gradle won't work with newer or older versions)
4. On Debian/Ubuntu: `sudo apt install python3-dev python3-venv`
5. On Fedora (if using LDAP source integration): `sudo yum install openldap-devel`

Expand Down
2 changes: 1 addition & 1 deletion metadata-ingestion/docs/sources/metabase/metabase.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ The key in this map must be string, not integer although Metabase API provides
If `database_id_to_instance_map` is not specified, `platform_instance_map` is used for platform instance mapping. If none of the above are specified, platform instance is not used when constructing `urn` when searching for dataset relations.
## Compatibility

Metabase version [v0.41.2](https://www.metabase.com/start/oss/)
Metabase version [v0.48.3](https://www.metabase.com/start/oss/)
47 changes: 32 additions & 15 deletions metadata-ingestion/src/datahub/ingestion/source/metabase.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,17 @@ class MetabaseSource(Source):
"""
This plugin extracts Charts, dashboards, and associated metadata. This plugin is in beta and has only been tested
on PostgreSQL and H2 database.
### Dashboard
[/api/dashboard](https://www.metabase.com/docs/latest/api-documentation.html#dashboard) endpoint is used to
retrieve the following dashboard information.
### Collection
[/api/collection](https://www.metabase.com/docs/latest/api/collection) endpoint is used to
retrieve the available collections.
[/api/collection/<COLLECTION_ID>/items?models=dashboard](https://www.metabase.com/docs/latest/api/collection#get-apicollectioniditems) endpoint is used to retrieve a given collection and list their dashboards.
### Dashboard
[/api/dashboard/<DASHBOARD_ID>](https://www.metabase.com/docs/latest/api/dashboard) endpoint is used to retrieve a given Dashboard and grab its information.
- Title and description
- Last edited by
Expand Down Expand Up @@ -187,19 +194,29 @@ def close(self) -> None:

def emit_dashboard_mces(self) -> Iterable[MetadataWorkUnit]:
try:
dashboard_response = self.session.get(
f"{self.config.connect_uri}/api/dashboard"
collections_response = self.session.get(
f"{self.config.connect_uri}/api/collection/"
)
dashboard_response.raise_for_status()
dashboards = dashboard_response.json()
collections_response.raise_for_status()
collections = collections_response.json()

for dashboard_info in dashboards:
dashboard_snapshot = self.construct_dashboard_from_api_data(
dashboard_info
for collection in collections:
collection_dashboards_response = self.session.get(
f"{self.config.connect_uri}/api/collection/{collection['id']}/items?models=dashboard"
)
if dashboard_snapshot is not None:
mce = MetadataChangeEvent(proposedSnapshot=dashboard_snapshot)
yield MetadataWorkUnit(id=dashboard_snapshot.urn, mce=mce)
collection_dashboards_response.raise_for_status()
collection_dashboards = collection_dashboards_response.json()

if not collection_dashboards.get("data"):
continue

for dashboard_info in collection_dashboards.get("data"):
dashboard_snapshot = self.construct_dashboard_from_api_data(
dashboard_info
)
if dashboard_snapshot is not None:
mce = MetadataChangeEvent(proposedSnapshot=dashboard_snapshot)
yield MetadataWorkUnit(id=dashboard_snapshot.urn, mce=mce)

except HTTPError as http_error:
self.report.report_failure(
Expand Down Expand Up @@ -254,10 +271,10 @@ def construct_dashboard_from_api_data(
)

chart_urns = []
cards_data = dashboard_details.get("ordered_cards", "{}")
cards_data = dashboard_details.get("dashcards", {})
for card_info in cards_data:
chart_urn = builder.make_chart_urn(
self.platform, card_info.get("card_id", "")
self.platform, card_info.get("card").get("id", "")
)
chart_urns.append(chart_urn)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,20 +191,73 @@
"description": "",
"charts": [
"urn:li:chart:(metabase,1)",
"urn:li:chart:(metabase,2)"
"urn:li:chart:(metabase,2)",
"urn:li:chart:(metabase,3)"
],
"datasets": [],
"lastModified": {
"created": {
"time": 1639417721742,
"time": 1705398694904,
"actor": "urn:li:corpuser:[email protected]"
},
"lastModified": {
"time": 1639417721742,
"time": 1705398694904,
"actor": "urn:li:corpuser:[email protected]"
}
},
"dashboardUrl": "http://localhost:3000/dashboard/1"
"dashboardUrl": "http://localhost:3000/dashboard/10"
}
},
{
"com.linkedin.pegasus2avro.common.Ownership": {
"owners": [
{
"owner": "urn:li:corpuser:[email protected]",
"type": "DATAOWNER"
}
],
"lastModified": {
"time": 0,
"actor": "urn:li:corpuser:unknown"
}
}
}
]
}
},
"systemMetadata": {
"lastObserved": 1636614000000,
"runId": "metabase-test",
"lastRunId": "no-run-id-provided"
}
},
{
"proposedSnapshot": {
"com.linkedin.pegasus2avro.metadata.snapshot.DashboardSnapshot": {
"urn": "urn:li:dashboard:(metabase,1)",
"aspects": [
{
"com.linkedin.pegasus2avro.dashboard.DashboardInfo": {
"customProperties": {},
"title": "Dashboard 1",
"description": "",
"charts": [
"urn:li:chart:(metabase,1)",
"urn:li:chart:(metabase,2)",
"urn:li:chart:(metabase,3)"
],
"datasets": [],
"lastModified": {
"created": {
"time": 1705398694904,
"actor": "urn:li:corpuser:[email protected]"
},
"lastModified": {
"time": 1705398694904,
"actor": "urn:li:corpuser:[email protected]"
}
},
"dashboardUrl": "http://localhost:3000/dashboard/10"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"total": 1, "data": [{"description": null, "collection_position": null, "database_id": null, "name": "This is a test", "id": 10, "entity_id": "Q4gEaOmoBkfQX3_gXiH9g", "last-edit-info": {"id": 14, "last_name": "Doe", "first_name": "John", "email": "[email protected]", "timestamp": "2024-01-12T14:55:38.43304Z"}, "model": "dashboard"}], "models": ["dashboard"], "limit": null, "offset": null}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"authority_level": null, "can_write": true, "name": "Our analytics", "effective_ancestors": [], "effective_location": null, "parent_id": null, "id": "root", "is_personal": false}, {"authority_level": null, "description": null, "archived": false, "slug": "john_doe_personal_collection", "can_write": true, "name": "John Doe", "personal_owner_id": 14, "type": null, "id": 150, "entity_id": "kdLA_-CQy4F5lL15k8-TU", "location": "/", "namespace": null, "is_personal": true, "created_at": "2024-01-12T11:51:24.394309Z"}]
40 changes: 0 additions & 40 deletions metadata-ingestion/tests/integration/metabase/setup/dashboard.json

This file was deleted.

Loading

0 comments on commit f7f0b14

Please sign in to comment.