11import json
22import logging
3+ from collections .abc import Callable , Iterable
34from datetime import timedelta
45from functools import partial
56
67from databricks .labs .blueprint .limiter import rate_limited
78from databricks .sdk import WorkspaceClient
89from databricks .sdk .retries import retried
910from databricks .sdk .service import workspace
11+ from databricks .sdk .service .workspace import AclItem
1012
1113from databricks .labs .ucx .workspace_access .base import AclSupport , Permissions
1214from databricks .labs .ucx .workspace_access .groups import MigrationState
@@ -58,7 +60,7 @@ def get_apply_task(self, item: Permissions, migration_state: MigrationState):
5860
5961 def apply_acls ():
6062 for acl in new_acls :
61- self ._rate_limited_put_acl (item .object_id , acl .principal , acl .permission )
63+ self ._applier_task (item .object_id , acl .principal , acl .permission )
6264 return True
6365
6466 return partial (apply_acls )
@@ -78,21 +80,42 @@ def secret_scope_permission(self, scope_name: str, group_name: str) -> workspace
7880 def _reapply_on_failure (self , scope_name : str , group_name : str , expected_permission : workspace .AclPermission ):
7981 # in-flight check for the applied permissions
8082 # the api might be inconsistent, therefore we need to check that the permissions were applied
81- applied_permission = self . secret_scope_permission ( scope_name , group_name )
82- if applied_permission != expected_permission :
83- # try to apply again if the permissions are not equal: sometimes the list_acls api is inconsistent
83+ try :
84+ self . _verify ( scope_name , group_name , expected_permission )
85+ except ValueError :
8486 logger .info (f"Applying permissions again { expected_permission } to { group_name } for { scope_name } " )
8587 self ._ws .secrets .put_acl (scope_name , group_name , expected_permission )
88+ raise
89+ return True
90+
91+ @rate_limited (max_requests = 1100 , burst_period_seconds = 60 )
92+ def _verify (self , scope_name : str , group_name : str , expected_permission : workspace .AclPermission ):
93+ # in-flight check for the applied permissions
94+ # the api might be inconsistent, therefore we need to check that the permissions were applied
95+ applied_permission = self .secret_scope_permission (scope_name , group_name )
96+ if applied_permission != expected_permission :
8697 msg = (
87- f"Applied permission { applied_permission } is not equal to expected "
88- f"permission { expected_permission } for { scope_name } and { group_name } !"
98+ f"Couldn't find permission for scope { scope_name } and group { group_name } \n "
99+ f"acl to be applied={ expected_permission } \n "
100+ f"acl found in the object={ applied_permission } \n "
89101 )
90102 raise ValueError (msg )
91- logger .info (f"Permissions matched for { scope_name } , { group_name } and { expected_permission } !" )
92103 return True
93104
105+ def get_verify_task (self , item : Permissions ) -> Callable [[], bool ]:
106+ acls = [workspace .AclItem .from_dict (acl ) for acl in json .loads (item .raw )]
107+
108+ def _verify_acls (scope_name : str , acls : Iterable [AclItem ]):
109+ for acl in acls :
110+ assert acl .permission is not None
111+ assert acl .principal is not None
112+ self ._verify (scope_name , acl .principal , acl .permission )
113+ return True
114+
115+ return partial (_verify_acls , item .object_id , acls )
116+
94117 @rate_limited (max_requests = 1100 , burst_period_seconds = 60 )
95- def _rate_limited_put_acl (self , object_id : str , principal : str , permission : workspace .AclPermission ):
118+ def _applier_task (self , object_id : str , principal : str , permission : workspace .AclPermission ):
96119 self ._ws .secrets .put_acl (object_id , principal , permission )
97120 retry_on_value_error = retried (on = [ValueError ], timeout = self ._verify_timeout )
98121 retried_check = retry_on_value_error (self ._reapply_on_failure )
0 commit comments