Skip to content

Commit b616354

Browse files
authored
Adopted databricks-labs-blueprint library (#758)
1 parent 260bef3 commit b616354

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+173
-1126
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ classifiers = [
2727
"Programming Language :: Python :: Implementation :: CPython",
2828
]
2929
dependencies = ["databricks-sdk~=0.16.0",
30+
"databricks-labs-blueprint",
3031
"PyYAML>=6.0.0,<7.0.0"]
3132

3233
[project.entry-points.databricks]

src/databricks/labs/ucx/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
from databricks.labs.ucx.framework.logger import _install
1+
from databricks.labs.blueprint.logger import install_logger
22

3-
_install()
3+
install_logger()

src/databricks/labs/ucx/account.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
from typing import ClassVar
44

55
import requests
6+
from databricks.labs.blueprint.tui import Prompts
67
from databricks.sdk import WorkspaceClient
78
from databricks.sdk.errors import NotFound
89
from databricks.sdk.service.provisioning import Workspace
910
from databricks.sdk.service.workspace import ImportFormat
1011

1112
from databricks.labs.ucx.__about__ import __version__
1213
from databricks.labs.ucx.config import AccountConfig
13-
from databricks.labs.ucx.framework.tui import Prompts
1414
from databricks.labs.ucx.installer import InstallationManager
1515

1616
logger = logging.getLogger(__name__)

src/databricks/labs/ucx/cli.py

Lines changed: 71 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,147 @@
11
import json
2-
import logging
3-
import sys
42
import webbrowser
53

6-
from databricks.sdk import WorkspaceClient
4+
from databricks.labs.blueprint.cli import App
5+
from databricks.labs.blueprint.entrypoint import get_logger
6+
from databricks.labs.blueprint.tui import Prompts
7+
from databricks.sdk import AccountClient, WorkspaceClient
78

89
from databricks.labs.ucx.account import AccountWorkspaces, WorkspaceInfo
910
from databricks.labs.ucx.config import AccountConfig, ConnectConfig
1011
from databricks.labs.ucx.framework.crawlers import StatementExecutionBackend
11-
from databricks.labs.ucx.framework.tui import Prompts
1212
from databricks.labs.ucx.hive_metastore import ExternalLocations, TablesCrawler
1313
from databricks.labs.ucx.hive_metastore.mapping import TableMapping
1414
from databricks.labs.ucx.hive_metastore.table_migrate import TablesMigrate
1515
from databricks.labs.ucx.install import WorkspaceInstaller
1616
from databricks.labs.ucx.installer import InstallationManager
1717

18-
logger = logging.getLogger("databricks.labs.ucx")
18+
ucx = App(__file__)
19+
logger = get_logger(__file__)
1920

2021
CANT_FIND_UCX_MSG = (
2122
"Couldn't find UCX configuration in the user's home folder. "
2223
"Make sure the current user has configured and installed UCX."
2324
)
2425

2526

26-
def workflows():
27-
ws = WorkspaceClient()
28-
installer = WorkspaceInstaller(ws)
27+
@ucx.command
28+
def workflows(w: WorkspaceClient):
29+
"""Show deployed workflows and their state"""
30+
installer = WorkspaceInstaller(w)
2931
logger.info("Fetching deployed jobs...")
3032
print(json.dumps(installer.latest_job_status()))
3133

3234

33-
def open_remote_config():
34-
ws = WorkspaceClient()
35-
installer = WorkspaceInstaller(ws)
35+
@ucx.command
36+
def open_remote_config(w: WorkspaceClient):
37+
"""Opens remote configuration in the browser"""
38+
installer = WorkspaceInstaller(w)
3639

3740
ws_file_url = installer.notebook_link(installer.config_file)
3841
webbrowser.open(ws_file_url)
3942

4043

41-
def list_installations():
42-
ws = WorkspaceClient()
43-
installation_manager = InstallationManager(ws)
44+
@ucx.command
45+
def installations(w: WorkspaceClient):
46+
"""Show installations by different users on the same workspace"""
47+
installation_manager = InstallationManager(w)
4448
logger.info("Fetching installations...")
4549
all_users = [_.as_summary() for _ in installation_manager.user_installations()]
4650
print(json.dumps(all_users))
4751

4852

49-
def skip(schema: str, table: str | None = None):
53+
@ucx.command
54+
def skip(w: WorkspaceClient, schema: str | None = None, table: str | None = None):
55+
"""Create a skip comment on a schema or a table"""
5056
logger.info("Running skip command")
5157
if not schema:
52-
logger.error("--Schema is a required parameter.")
58+
logger.error("--schema is a required parameter.")
5359
return None
54-
ws = WorkspaceClient()
55-
installation_manager = InstallationManager(ws)
56-
installation = installation_manager.for_user(ws.current_user.me())
60+
installation_manager = InstallationManager(w)
61+
installation = installation_manager.for_user(w.current_user.me())
5762
if not installation:
5863
logger.error(CANT_FIND_UCX_MSG)
5964
return None
6065
warehouse_id = installation.config.warehouse_id
61-
sql_backend = StatementExecutionBackend(ws, warehouse_id)
62-
mapping = TableMapping(ws)
66+
sql_backend = StatementExecutionBackend(w, warehouse_id)
67+
mapping = TableMapping(w)
6368
if table:
6469
mapping.skip_table(sql_backend, schema, table)
6570
else:
6671
mapping.skip_schema(sql_backend, schema)
6772

6873

69-
def sync_workspace_info():
74+
@ucx.command(is_account=True)
75+
def sync_workspace_info(a: AccountClient):
76+
"""upload workspace config to all workspaces in the account where ucx is installed"""
77+
logger.info(f"Account ID: {a.config.account_id}")
7078
workspaces = AccountWorkspaces(AccountConfig(connect=ConnectConfig()))
7179
workspaces.sync_workspace_info()
7280

7381

74-
def manual_workspace_info():
75-
ws = WorkspaceClient()
82+
@ucx.command
83+
def manual_workspace_info(w: WorkspaceClient):
84+
"""only supposed to be run if cannot get admins to run `databricks labs ucx sync-workspace-info`"""
7685
prompts = Prompts()
77-
workspace_info = WorkspaceInfo(ws)
86+
workspace_info = WorkspaceInfo(w)
7887
workspace_info.manual_workspace_info(prompts)
7988

8089

81-
def create_table_mapping():
82-
ws = WorkspaceClient()
83-
table_mapping = TableMapping(ws)
84-
workspace_info = WorkspaceInfo(ws)
85-
installation_manager = InstallationManager(ws)
86-
installation = installation_manager.for_user(ws.current_user.me())
87-
sql_backend = StatementExecutionBackend(ws, installation.config.warehouse_id)
90+
@ucx.command
91+
def create_table_mapping(w: WorkspaceClient):
92+
"""create initial table mapping for review"""
93+
table_mapping = TableMapping(w)
94+
workspace_info = WorkspaceInfo(w)
95+
installation_manager = InstallationManager(w)
96+
installation = installation_manager.for_user(w.current_user.me())
97+
sql_backend = StatementExecutionBackend(w, installation.config.warehouse_id)
8898
tables_crawler = TablesCrawler(sql_backend, installation.config.inventory_database)
8999
path = table_mapping.save(tables_crawler, workspace_info)
90-
webbrowser.open(f"{ws.config.host}/#workspace{path}")
100+
webbrowser.open(f"{w.config.host}/#workspace{path}")
91101

92102

93-
def validate_external_locations():
94-
ws = WorkspaceClient()
103+
@ucx.command
104+
def validate_external_locations(w: WorkspaceClient):
105+
"""validates and provides mapping to external table to external location and shared generation tf scripts"""
95106
prompts = Prompts()
96-
installation_manager = InstallationManager(ws)
97-
installation = installation_manager.for_user(ws.current_user.me())
98-
sql_backend = StatementExecutionBackend(ws, installation.config.warehouse_id)
99-
location_crawler = ExternalLocations(ws, sql_backend, installation.config.inventory_database)
107+
installation_manager = InstallationManager(w)
108+
installation = installation_manager.for_user(w.current_user.me())
109+
sql_backend = StatementExecutionBackend(w, installation.config.warehouse_id)
110+
location_crawler = ExternalLocations(w, sql_backend, installation.config.inventory_database)
100111
path = location_crawler.save_as_terraform_definitions_on_workspace(installation.path)
101112
if path and prompts.confirm(f"external_locations.tf file written to {path}. Do you want to open it?"):
102-
webbrowser.open(f"{ws.config.host}/#workspace{path}")
113+
webbrowser.open(f"{w.config.host}/#workspace{path}")
103114

104115

105-
def ensure_assessment_run():
106-
ws = WorkspaceClient()
107-
installation_manager = InstallationManager(ws)
108-
installation = installation_manager.for_user(ws.current_user.me())
116+
@ucx.command
117+
def ensure_assessment_run(w: WorkspaceClient):
118+
"""ensure the assessment job was run on a workspace"""
119+
installation_manager = InstallationManager(w)
120+
installation = installation_manager.for_user(w.current_user.me())
109121
if not installation:
110122
logger.error(CANT_FIND_UCX_MSG)
111123
return None
112124
else:
113-
workspace_installer = WorkspaceInstaller(ws)
125+
workspace_installer = WorkspaceInstaller(w)
114126
workspace_installer.validate_and_run("assessment")
115127

116128

117-
def repair_run(step):
129+
@ucx.command
130+
def repair_run(w: WorkspaceClient, step):
131+
"""Repair Run the Failed Job"""
118132
if not step:
119133
raise KeyError("You did not specify --step")
120-
ws = WorkspaceClient()
121-
installer = WorkspaceInstaller(ws)
134+
installer = WorkspaceInstaller(w)
122135
logger.info(f"Repair Running {step} Job")
123136
installer.repair_run(step)
124137

125138

126-
def revert_migrated_tables(schema: str, table: str, *, delete_managed: bool = False):
127-
ws = WorkspaceClient()
139+
@ucx.command
140+
def revert_migrated_tables(w: WorkspaceClient, schema: str, table: str, *, delete_managed: bool = False):
141+
"""remove notation on a migrated table for re-migration"""
128142
prompts = Prompts()
129-
installation_manager = InstallationManager(ws)
130-
installation = installation_manager.for_user(ws.current_user.me())
143+
installation_manager = InstallationManager(w)
144+
installation = installation_manager.for_user(w.current_user.me())
131145
if not schema and not table:
132146
if not prompts.confirm(
133147
"You haven't specified a schema or a table. All migrated tables will be reverted."
@@ -139,46 +153,15 @@ def revert_migrated_tables(schema: str, table: str, *, delete_managed: bool = Fa
139153
logger.error(CANT_FIND_UCX_MSG)
140154
return None
141155
warehouse_id = installation.config.warehouse_id
142-
sql_backend = StatementExecutionBackend(ws, warehouse_id)
156+
sql_backend = StatementExecutionBackend(w, warehouse_id)
143157
table_crawler = TablesCrawler(sql_backend, installation.config.inventory_database)
144-
tmp = TableMapping(ws)
145-
tm = TablesMigrate(table_crawler, ws, sql_backend, tmp)
158+
tmp = TableMapping(w)
159+
tm = TablesMigrate(table_crawler, w, sql_backend, tmp)
146160
if tm.print_revert_report(delete_managed=delete_managed) and prompts.confirm(
147161
"Would you like to continue?", max_attempts=2
148162
):
149163
tm.revert_migrated_tables(schema, table, delete_managed=delete_managed)
150164

151165

152-
MAPPING = {
153-
"open-remote-config": open_remote_config,
154-
"installations": list_installations,
155-
"workflows": workflows,
156-
"sync-workspace-info": sync_workspace_info,
157-
"manual-workspace-info": manual_workspace_info,
158-
"create-table-mapping": create_table_mapping,
159-
"validate-external-locations": validate_external_locations,
160-
"ensure-assessment-run": ensure_assessment_run,
161-
"skip": skip,
162-
"repair-run": repair_run,
163-
"revert-migrated-tables": revert_migrated_tables,
164-
}
165-
166-
167-
def main(raw):
168-
payload = json.loads(raw)
169-
command = payload["command"]
170-
if command not in MAPPING:
171-
msg = f"cannot find command: {command}"
172-
raise KeyError(msg)
173-
flags = payload["flags"]
174-
log_level = flags.pop("log_level")
175-
if log_level == "disabled":
176-
log_level = "info"
177-
databricks_logger = logging.getLogger("databricks")
178-
databricks_logger.setLevel(log_level.upper())
179-
kwargs = {k.replace("-", "_"): v for k, v in flags.items()}
180-
MAPPING[command](**kwargs)
181-
182-
183-
if __name__ == "__main__":
184-
main(*sys.argv[1:])
166+
if "__main__" == __name__:
167+
ucx()

src/databricks/labs/ucx/framework/dashboards.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from json import JSONDecodeError
77
from pathlib import Path
88

9+
from databricks.labs.blueprint.installer import InstallState
910
from databricks.sdk import WorkspaceClient
1011
from databricks.sdk.errors import DatabricksError, NotFound
1112
from databricks.sdk.service import workspace
@@ -18,8 +19,6 @@
1819
WidgetPosition,
1920
)
2021

21-
from databricks.labs.ucx.framework.install_state import InstallState
22-
2322
logger = logging.getLogger(__name__)
2423

2524

@@ -143,6 +142,7 @@ def _install_widget(self, query: SimpleQuery, dashboard_ref: str):
143142
widget = self._ws.dashboard_widgets.create(
144143
dashboard_id, widget_options, 1, visualization_id=self._state.viz[query.key]
145144
)
145+
assert widget.id is not None
146146
self._state.widgets[query.key] = widget.id
147147

148148
def _get_widget_options(self, query: SimpleQuery):
@@ -280,6 +280,7 @@ def _install_viz(self, query: SimpleQuery):
280280
if query.key in self._state.viz:
281281
return self._ws.query_visualizations.update(self._state.viz[query.key], **viz_args)
282282
viz = self._ws.query_visualizations.create(self._state.queries[query.key], **viz_args)
283+
assert viz.id is not None
283284
self._state.viz[query.key] = viz.id
284285

285286
def _get_viz_options(self, query: SimpleQuery):

src/databricks/labs/ucx/framework/install_state.py

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)