99
1010from databricks .labs .ucx .framework .crawlers import CrawlerBase
1111from databricks .labs .ucx .hive_metastore .tables import TablesCrawler
12+ from databricks .labs .ucx .hive_metastore .udfs import UdfsCrawler
1213
1314logger = logging .getLogger (__name__ )
1415
@@ -21,6 +22,7 @@ class Grant:
2122 database : str | None = None
2223 table : str | None = None
2324 view : str | None = None
25+ udf : str | None = None
2426 any_file : bool = False
2527 anonymous_function : bool = False
2628
@@ -31,6 +33,7 @@ def type_and_key(
3133 database : str | None = None ,
3234 table : str | None = None ,
3335 view : str | None = None ,
36+ udf : str | None = None ,
3437 any_file : bool = False ,
3538 anonymous_function : bool = False ,
3639 ) -> tuple [str , str ]:
@@ -42,6 +45,10 @@ def type_and_key(
4245 catalog = "hive_metastore" if catalog is None else catalog
4346 database = "default" if database is None else database
4447 return "VIEW" , f"{ catalog } .{ database } .{ view } "
48+ if udf is not None :
49+ catalog = "hive_metastore" if catalog is None else catalog
50+ database = "default" if database is None else database
51+ return "FUNCTION" , f"{ catalog } .{ database } .{ udf } "
4552 if database is not None :
4653 catalog = "hive_metastore" if catalog is None else catalog
4754 return "DATABASE" , f"{ catalog } .{ database } "
@@ -53,7 +60,7 @@ def type_and_key(
5360 if catalog is not None :
5461 return "CATALOG" , catalog
5562 msg = (
56- f"invalid grant keys: catalog={ catalog } , database={ database } , view={ view } , "
63+ f"invalid grant keys: catalog={ catalog } , database={ database } , view={ view } , udf= { udf } "
5764 f"any_file={ any_file } , anonymous_function={ anonymous_function } "
5865 )
5966 raise ValueError (msg )
@@ -69,6 +76,7 @@ def this_type_and_key(self):
6976 database = self .database ,
7077 table = self .table ,
7178 view = self .view ,
79+ udf = self .udf ,
7280 any_file = self .any_file ,
7381 anonymous_function = self .anonymous_function ,
7482 )
@@ -135,9 +143,13 @@ def uc_grant_sql(self):
135143
136144
137145class GrantsCrawler (CrawlerBase [Grant ]):
138- def __init__ (self , tc : TablesCrawler ):
146+ def __init__ (self , tc : TablesCrawler , udf : UdfsCrawler ):
147+ assert tc ._backend == udf ._backend
148+ assert tc ._catalog == udf ._catalog
149+ assert tc ._schema == udf ._schema
139150 super ().__init__ (tc ._backend , tc ._catalog , tc ._schema , "grants" , Grant )
140151 self ._tc = tc
152+ self ._udf = udf
141153
142154 def snapshot (self ) -> Iterable [Grant ]:
143155 return self ._snapshot (partial (self ._try_load ), partial (self ._crawl ))
@@ -148,7 +160,7 @@ def _try_load(self):
148160
149161 def _crawl (self ) -> Iterable [Grant ]:
150162 """
151- Crawls and lists grants for all databases, tables, views, any file
163+ Crawls and lists grants for all databases, tables, views, udfs, any file
152164 and anonymous function within hive_metastore.
153165
154166 Returns:
@@ -159,12 +171,14 @@ def _crawl(self) -> Iterable[Grant]:
159171 table/view-specific grants.
160172 - Iterates through tables in the specified database using the `_tc.snapshot` method.
161173 - For each table, adds tasks to fetch grants for the table or its view, depending on the kind of the table.
174+ - Iterates through udfs in the specified database using the `_udf.snapshot` method.
175+ - For each udf, adds tasks to fetch grants for the udf.
162176 - Executes the tasks concurrently using Threads.gather.
163177 - Flattens the list of retrieved grant lists into a single list of Grant objects.
164178
165179 Note:
166180 - The method assumes that the `_grants` method fetches grants based on the provided parameters (catalog,
167- database, table, view, any file, anonymous function).
181+ database, table, view, udfs, any file, anonymous function).
168182
169183 Returns:
170184 list[Grant]: A list of Grant objects representing the grants found in hive_metastore.
@@ -181,6 +195,9 @@ def _crawl(self) -> Iterable[Grant]:
181195 fn = partial (self ._grants , catalog = catalog , database = table .database )
182196 # views are recognized as tables
183197 tasks .append (partial (fn , table = table .name ))
198+ for udf in self ._udf .snapshot ():
199+ fn = partial (self ._grants , catalog = catalog , database = udf .database )
200+ tasks .append (partial (fn , udf = udf .name ))
184201 catalog_grants , errors = Threads .gather (f"listing grants for { catalog } " , tasks )
185202 if len (errors ) > 0 :
186203 raise ManyError (errors )
@@ -206,6 +223,7 @@ def _grants(
206223 database : str | None = None ,
207224 table : str | None = None ,
208225 view : str | None = None ,
226+ udf : str | None = None ,
209227 any_file : bool = False ,
210228 anonymous_function : bool = False ,
211229 ) -> list [Grant ]:
@@ -217,6 +235,7 @@ def _grants(
217235 database (str | None): The database name (optional).
218236 table (str | None): The table name (optional).
219237 view (str | None): The view name (optional).
238+ udf (str | None): The udf name (optional).
220239 any_file (bool): Whether to include any file grants (optional).
221240 anonymous_function (bool): Whether to include anonymous function grants (optional).
222241
@@ -245,13 +264,12 @@ def _grants(
245264 database = self ._try_valid (database ),
246265 table = self ._try_valid (table ),
247266 view = self ._try_valid (view ),
267+ udf = self ._try_valid (udf ),
248268 any_file = any_file ,
249269 anonymous_function = anonymous_function ,
250270 )
251271 try :
252272 grants = []
253- # Added ANY FILE and ANONYMOUS FUNCTION in object_type_normalization
254- # to capture the same in grants. issue:#623
255273 object_type_normalization = {
256274 "SCHEMA" : "DATABASE" ,
257275 "CATALOG$" : "CATALOG" ,
@@ -271,6 +289,7 @@ def _grants(
271289 action_type = action_type ,
272290 table = table ,
273291 view = view ,
292+ udf = udf ,
274293 database = database ,
275294 catalog = catalog ,
276295 any_file = any_file ,
0 commit comments