Skip to content

Commit e7bcf5d

Browse files
authored
Tune verify testing (#177)
1 parent d87403c commit e7bcf5d

File tree

8 files changed

+81
-217
lines changed

8 files changed

+81
-217
lines changed

src/databricks/labs/ucx/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ class MigrationConfig:
117117
num_threads: int | None = 4
118118
log_level: str | None = "INFO"
119119

120+
# Starting path for notebooks and directories crawler
121+
workspace_start_path: str = "/"
122+
120123
def __post_init__(self):
121124
if self.connect is None:
122125
self.connect = ConnectConfig()

src/databricks/labs/ucx/inventory/inventorizer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ def inner() -> Iterator[ModelDatabricks]:
373373

374374
class Inventorizers:
375375
@staticmethod
376-
def provide(ws: WorkspaceClient, migration_state: GroupMigrationState, num_threads: int):
376+
def provide(ws: WorkspaceClient, migration_state: GroupMigrationState, num_threads: int, start_path: str):
377377
return [
378378
RolesAndEntitlementsInventorizer(ws, migration_state),
379379
TokensAndPasswordsInventorizer(ws),
@@ -434,5 +434,5 @@ def provide(ws: WorkspaceClient, migration_state: GroupMigrationState, num_threa
434434
id_attribute="id",
435435
),
436436
SecretScopeInventorizer(ws),
437-
WorkspaceInventorizer(ws, num_threads=num_threads),
437+
WorkspaceInventorizer(ws, num_threads=num_threads, start_path=start_path),
438438
]

src/databricks/labs/ucx/inventory/permissions.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,16 @@ def apply_group_permissions(self, migration_state: GroupMigrationState, destinat
301301
self._apply_permissions_in_parallel(requests=permission_payloads)
302302
logger.info(f"All permissions were applied for {destination} groups")
303303

304+
def verify(
305+
self, migration_state: GroupMigrationState, target: Literal["backup", "account"], tuples: list[tuple[str, str]]
306+
):
307+
for object_type, object_id in tuples:
308+
if object_type == LogicalObjectType.SECRET_SCOPE:
309+
self.verify_applied_scope_acls(object_id, migration_state, target)
310+
else:
311+
self.verify_applied_permissions(object_type, object_id, migration_state, target)
312+
self.verify_roles_and_entitlements(migration_state, target)
313+
304314
def verify_applied_permissions(
305315
self,
306316
object_type: str,
@@ -336,6 +346,17 @@ def verify_applied_scope_acls(
336346
dst_permission = self._secret_scope_permission(scope_name, dst_name)
337347
assert src_permission == dst_permission, "Scope ACLs were not applied correctly"
338348

349+
def verify_roles_and_entitlements(self, migration_state: GroupMigrationState, target: Literal["backup", "account"]):
350+
for el in migration_state.groups:
351+
comparison_base = getattr(el, "workspace" if target == "backup" else "backup")
352+
comparison_target = getattr(el, target)
353+
354+
base_group_info = self._ws.groups.get(comparison_base.id)
355+
target_group_info = self._ws.groups.get(comparison_target.id)
356+
357+
assert base_group_info.roles == target_group_info.roles
358+
assert base_group_info.entitlements == target_group_info.entitlements
359+
339360
def _secret_scope_permission(self, scope_name: str, group_name: str) -> workspace.AclPermission | None:
340361
for acl in self._ws.secrets.list_acls(scope=scope_name):
341362
if acl.principal == group_name:

src/databricks/labs/ucx/toolkits/group_migration.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
class GroupMigrationToolkit:
1313
def __init__(self, config: MigrationConfig):
1414
self._num_threads = config.num_threads
15+
self._workspace_start_path = config.workspace_start_path
1516

1617
databricks_config = config.to_databricks_config()
1718
self._configure_logger(config.log_level)
@@ -22,9 +23,9 @@ def __init__(self, config: MigrationConfig):
2223
self._ws.api_client._session.adapters["https://"].max_retries.total = 20
2324
self._verify_ws_client(self._ws)
2425

25-
self.group_manager = GroupManager(self._ws, config.groups)
26-
self.table_manager = InventoryTableManager(config.inventory, self._ws)
27-
self.permissions_manager = PermissionManager(self._ws, self.table_manager)
26+
self._group_manager = GroupManager(self._ws, config.groups)
27+
self._table_manager = InventoryTableManager(config.inventory, self._ws)
28+
self._permissions_manager = PermissionManager(self._ws, self._table_manager)
2829

2930
@staticmethod
3031
def _verify_ws_client(w: WorkspaceClient):
@@ -40,28 +41,36 @@ def _configure_logger(level: str):
4041
ucx_logger.setLevel(level)
4142

4243
def prepare_environment(self):
43-
self.group_manager.prepare_groups_in_environment()
44-
inventorizers = Inventorizers.provide(self._ws, self.group_manager.migration_groups_provider, self._num_threads)
45-
self.permissions_manager.set_inventorizers(inventorizers)
44+
self._group_manager.prepare_groups_in_environment()
45+
inventorizers = Inventorizers.provide(
46+
self._ws, self._group_manager.migration_groups_provider, self._num_threads, self._workspace_start_path
47+
)
48+
self._permissions_manager.set_inventorizers(inventorizers)
4649

4750
def cleanup_inventory_table(self):
48-
self.table_manager.cleanup()
51+
self._table_manager.cleanup()
4952

5053
def inventorize_permissions(self):
51-
self.permissions_manager.inventorize_permissions()
54+
self._permissions_manager.inventorize_permissions()
5255

5356
def apply_permissions_to_backup_groups(self):
54-
self.permissions_manager.apply_group_permissions(
55-
self.group_manager.migration_groups_provider, destination="backup"
57+
self._permissions_manager.apply_group_permissions(
58+
self._group_manager.migration_groups_provider, destination="backup"
5659
)
5760

61+
def verify_permissions_on_backup_groups(self, to_verify):
62+
self._permissions_manager.verify(self._group_manager.migration_groups_provider, "backup", to_verify)
63+
5864
def replace_workspace_groups_with_account_groups(self):
59-
self.group_manager.replace_workspace_groups_with_account_groups()
65+
self._group_manager.replace_workspace_groups_with_account_groups()
6066

6167
def apply_permissions_to_account_groups(self):
62-
self.permissions_manager.apply_group_permissions(
63-
self.group_manager.migration_groups_provider, destination="account"
68+
self._permissions_manager.apply_group_permissions(
69+
self._group_manager.migration_groups_provider, destination="account"
6470
)
6571

72+
def verify_permissions_on_account_groups(self, to_verify):
73+
self._permissions_manager.verify(self._group_manager.migration_groups_provider, "account", to_verify)
74+
6675
def delete_backup_groups(self):
67-
self.group_manager.delete_backup_groups()
76+
self._group_manager.delete_backup_groups()

tests/integration/conftest.py

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import json
21
import logging
32
import os
43
import random
@@ -9,24 +8,16 @@
98
from databricks.sdk import AccountClient, WorkspaceClient
109
from databricks.sdk.core import Config
1110

12-
from databricks.labs.ucx.config import InventoryTable
1311
from databricks.labs.ucx.providers.mixins.fixtures import * # noqa: F403
1412
from databricks.labs.ucx.providers.mixins.sql import StatementExecutionExt
1513
from databricks.labs.ucx.utils import ThreadedExecution
1614

17-
from .utils import EnvironmentInfo, InstanceProfile
18-
1915
logging.getLogger("tests").setLevel("DEBUG")
2016
logging.getLogger("databricks.labs.ucx").setLevel("DEBUG")
2117

2218
logger = logging.getLogger(__name__)
2319

24-
NUM_TEST_INSTANCE_PROFILES = int(os.environ.get("NUM_TEST_INSTANCE_PROFILES", 3))
25-
NUM_TEST_TOKENS = int(os.environ.get("NUM_TEST_TOKENS", 3))
26-
27-
NUM_THREADS = int(os.environ.get("NUM_TEST_THREADS", 20))
28-
UCX_TESTING_PREFIX = os.environ.get("UCX_TESTING_PREFIX", "ucx")
29-
Threader = partial(ThreadedExecution, num_threads=NUM_THREADS)
20+
Threader = partial(ThreadedExecution, num_threads=20)
3021
load_debug_env_if_runs_from_ide("ucws") # noqa: F405
3122

3223

@@ -188,62 +179,3 @@ def inner():
188179
return ws_group, acc_group
189180

190181
return inner
191-
192-
193-
@pytest.fixture
194-
def env(make_ucx_group, make_random) -> EnvironmentInfo:
195-
test_uid = f"ucx_{make_random(4)}"
196-
yield EnvironmentInfo(test_uid=test_uid, groups=[make_ucx_group()])
197-
198-
199-
@pytest.fixture
200-
def instance_profiles(env: EnvironmentInfo, ws: WorkspaceClient) -> list[InstanceProfile]:
201-
logger.debug("Adding test instance profiles")
202-
profiles: list[InstanceProfile] = []
203-
204-
for i in range(NUM_TEST_INSTANCE_PROFILES):
205-
profile_arn = f"arn:aws:iam::123456789:instance-profile/{env.test_uid}-test-{i}"
206-
iam_role_arn = f"arn:aws:iam::123456789:role/{env.test_uid}-test-{i}"
207-
ws.instance_profiles.add(instance_profile_arn=profile_arn, iam_role_arn=iam_role_arn, skip_validation=True)
208-
profiles.append(InstanceProfile(instance_profile_arn=profile_arn, iam_role_arn=iam_role_arn))
209-
210-
for ws_group, _ in env.groups:
211-
if random.choice([True, False]):
212-
# randomize to apply roles randomly
213-
roles = {
214-
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
215-
"Operations": [
216-
{
217-
"op": "add",
218-
"path": "roles",
219-
"value": [{"value": p.instance_profile_arn} for p in random.choices(profiles, k=2)],
220-
}
221-
],
222-
}
223-
ws.api_client.do("PATCH", f"/api/2.0/preview/scim/v2/Groups/{ws_group.id}", data=json.dumps(roles))
224-
225-
yield profiles
226-
227-
logger.debug("Deleting test instance profiles")
228-
for profile in profiles:
229-
ws.instance_profiles.remove(profile.instance_profile_arn)
230-
logger.debug("Test instance profiles deleted")
231-
232-
233-
@pytest.fixture()
234-
def inventory_table(env: EnvironmentInfo, ws: WorkspaceClient, make_catalog, make_schema) -> InventoryTable:
235-
catalog, schema = make_schema(make_catalog()).split(".")
236-
table = InventoryTable(
237-
catalog=catalog,
238-
database=schema,
239-
name=f"test_inventory_{env.test_uid}",
240-
)
241-
242-
yield table
243-
244-
logger.debug(f"Cleaning up inventory table {table}")
245-
try:
246-
ws.tables.delete(table.to_spark())
247-
logger.debug(f"Inventory table {table} deleted")
248-
except Exception as e:
249-
logger.warning(f"Cannot delete inventory table, skipping it. Original exception {e}")

0 commit comments

Comments
 (0)