@@ -1306,6 +1306,8 @@ def setup_class(cls):
13061306 "enable_database_admin"
13071307 ],
13081308 domain_login_only = False ,
1309+ enforce_user_token_requirement = True ,
1310+ default_clusteradmin = "root@builtin" ,
13091311 ))
13101312 cls .cluster .start ()
13111313
@@ -1317,15 +1319,17 @@ def setup_class(cls):
13171319 storage_pool_units_count = {
13181320 'hdd' : 1
13191321 },
1320- timeout_seconds = 100
1322+ timeout_seconds = 100 ,
1323+ token = cls .cluster .config .default_clusteradmin
13211324 )
13221325
13231326 cls .database_nodes = cls .cluster .register_and_start_slots (cls .database , count = 3 )
1324- cls .cluster .wait_tenant_up (cls .database )
1327+ cls .cluster .wait_tenant_up (cls .database , cls . cluster . config . default_clusteradmin )
13251328
13261329 driver_config = ydb .DriverConfig (
13271330 database = cls .database ,
1328- endpoint = "%s:%s" % (cls .cluster .nodes [1 ].host , cls .cluster .nodes [1 ].port ))
1331+ endpoint = "%s:%s" % (cls .cluster .nodes [1 ].host , cls .cluster .nodes [1 ].port ),
1332+ credentials = ydb .AuthTokenCredentials (cls .cluster .config .default_clusteradmin ))
13291333 cls .driver = ydb .Driver (driver_config )
13301334 cls .driver .wait (timeout = 4 )
13311335
@@ -1340,8 +1344,8 @@ def set_test_name(cls, request):
13401344 cls .test_name = request .node .name
13411345
13421346 @classmethod
1343- def create_backup (cls , command , expected_files , additional_args = []):
1344- backup_files_dir = output_path (cls .test_name , "backup_files_dir" )
1347+ def create_backup (cls , command , expected_files , output , additional_args = [], token = "" ):
1348+ backup_files_dir = output_path (cls .test_name , output )
13451349 execution = yatest .common .execute (
13461350 [
13471351 backup_bin (),
@@ -1350,7 +1354,8 @@ def create_backup(cls, command, expected_files, additional_args=[]):
13501354 ]
13511355 + command
13521356 + ["--output" , backup_files_dir ]
1353- + additional_args
1357+ + additional_args ,
1358+ env = {"YDB_TOKEN" : token }
13541359 )
13551360
13561361 list_result = fs_recursive_list (backup_files_dir , ListMode .FILES )
@@ -1370,32 +1375,59 @@ def create_backup(cls, command, expected_files, additional_args=[]):
13701375 )
13711376
13721377 @classmethod
1373- def create_cluster_backup (cls , expected_files , additional_args = []):
1378+ def create_cluster_backup (cls , expected_files , output = "backup_files_dir" , additional_args = []):
13741379 cls .create_backup (
13751380 [
13761381 "--database" , cls .root_dir ,
13771382 "admin" , "cluster" , "dump" ,
13781383 ],
13791384 expected_files ,
1380- additional_args
1385+ output ,
1386+ additional_args ,
1387+ token = cls .cluster .config .default_clusteradmin ,
13811388 )
13821389
13831390 @classmethod
1384- def create_database_backup (cls , expected_files , additional_args = []):
1391+ def create_database_backup (cls , expected_files , output = "backup_files_dir" , additional_args = []):
13851392 cls .create_backup (
13861393 [
13871394 "--database" , cls .database ,
1395+ "--user" , "dbadmin1" , "--no-password" ,
13881396 "admin" , "database" , "dump" ,
13891397 ],
13901398 expected_files ,
1399+ output ,
13911400 additional_args
13921401 )
13931402
1403+ @classmethod
1404+ def setup_sample_data (cls ):
1405+ pool = ydb .SessionPool (cls .driver )
1406+ with pool .checkout () as session :
1407+ session .execute_scheme ("CREATE GROUP people" )
1408+ session .execute_scheme ("CREATE USER alice PASSWORD '1234'" )
1409+ session .execute_scheme ("CREATE USER bob PASSWORD '1234'" )
1410+ session .execute_scheme ("ALTER GROUP people ADD USER alice" )
1411+ session .execute_scheme ("ALTER GROUP people ADD USER bob" )
1412+
1413+ session .execute_scheme ("CREATE GROUP dbadmins" )
1414+ session .execute_scheme ("CREATE USER dbadmin1" )
1415+ session .execute_scheme ("CREATE USER dbadmin2 PASSWORD '1234'" )
1416+ session .execute_scheme ("ALTER GROUP dbadmins ADD USER dbadmin1" )
1417+ session .execute_scheme ("ALTER GROUP dbadmins ADD USER dbadmin2" )
1418+ session .execute_scheme (f'GRANT "ydb.generic.use" on `{ cls .database } ` TO dbadmins' )
1419+
1420+ cls .driver .scheme_client .modify_permissions (
1421+ cls .database ,
1422+ ydb .ModifyPermissionsSettings ().change_owner ("dbadmins" )
1423+ )
1424+
1425+ create_table_with_data (cls .driver .table_client .session ().create (), "db1/table" )
1426+
13941427
13951428class TestClusterBackup (BaseTestClusterBackupInFiles ):
13961429 def test_cluster_backup (self ):
1397- session = self .driver .table_client .session ().create ()
1398- create_table_with_data (session , "db1/table" )
1430+ self .setup_sample_data ()
13991431
14001432 self .create_cluster_backup (expected_files = [
14011433 # cluster metadata
@@ -1415,8 +1447,7 @@ def test_cluster_backup(self):
14151447
14161448class TestDatabaseBackup (BaseTestClusterBackupInFiles ):
14171449 def test_database_backup (self ):
1418- session = self .driver .table_client .session ().create ()
1419- create_table_with_data (session , "db1/table" )
1450+ self .setup_sample_data ()
14201451
14211452 self .create_database_backup (expected_files = [
14221453 # database metadata
@@ -1431,3 +1462,162 @@ def test_database_backup(self):
14311462 "table/permissions.pb" ,
14321463 "table/data_00.csv" ,
14331464 ])
1465+
1466+
1467+ class BaseTestMultipleClusterBackupInFiles (BaseTestClusterBackupInFiles ):
1468+ @classmethod
1469+ def setup_class (cls ):
1470+ super ().setup_class ()
1471+
1472+ cfg = KikimrConfigGenerator (
1473+ extra_feature_flags = [
1474+ "enable_strict_acl_check" ,
1475+ "enable_strict_user_management" ,
1476+ "enable_database_admin"
1477+ ],
1478+ domain_name = "Root2" ,
1479+ domain_login_only = False ,
1480+ enforce_user_token_requirement = True ,
1481+ default_clusteradmin = "root@builtin" ,
1482+ )
1483+
1484+ cls .restore_cluster = KiKiMR (
1485+ cfg ,
1486+ cluster_name = "restore_cluster"
1487+ )
1488+
1489+ cls .restore_cluster .start ()
1490+
1491+ cls .restore_root_dir = "/Root2"
1492+ cls .restore_database = os .path .join (cls .restore_root_dir , "db1" )
1493+ cls .restore_database_nodes = cls .restore_cluster .register_and_start_slots (
1494+ cls .restore_database ,
1495+ count = 1
1496+ )
1497+
1498+ restore_driver_config = ydb .DriverConfig (
1499+ database = cls .restore_database ,
1500+ endpoint = "%s:%s" % (
1501+ cls .restore_cluster .nodes [1 ].host ,
1502+ cls .restore_cluster .nodes [1 ].port
1503+ ),
1504+ credentials = ydb .AuthTokenCredentials (cls .cluster .config .default_clusteradmin ),
1505+ )
1506+ cls .restore_driver = ydb .Driver (restore_driver_config )
1507+
1508+ @classmethod
1509+ def teardown_class (cls ):
1510+ cls .restore_cluster .unregister_and_stop_slots (cls .restore_database_nodes )
1511+ cls .restore_cluster .stop ()
1512+ super ().teardown_class ()
1513+
1514+ @classmethod
1515+ def restore (cls , command , input , additional_args = [], token = "" ):
1516+ backup_files_dir = os .path .join (
1517+ yatest .common .output_path (),
1518+ cls .test_name ,
1519+ input
1520+ )
1521+
1522+ yatest .common .execute (
1523+ [
1524+ backup_bin (),
1525+ "--verbose" ,
1526+ "--assume-yes" ,
1527+ "--endpoint" , f"grpc://localhost:{ cls .restore_cluster .nodes [1 ].grpc_port } " ,
1528+ ]
1529+ + command
1530+ + ["--input" , backup_files_dir , "-w" , "60s" ]
1531+ + additional_args ,
1532+ env = {"YDB_TOKEN" : token }
1533+ )
1534+
1535+ @classmethod
1536+ def restore_cluster_backup (cls , input = "backup_files_dir" , additional_args = []):
1537+ cls .restore (
1538+ [
1539+ "--database" , cls .restore_root_dir ,
1540+ "admin" , "cluster" , "restore"
1541+ ],
1542+ input ,
1543+ additional_args ,
1544+ token = cls .restore_cluster .config .default_clusteradmin ,
1545+ )
1546+
1547+ @classmethod
1548+ def restore_database_backup (cls , input = "backup_files_dir" , additional_args = []):
1549+ cls .restore (
1550+ [
1551+ "--database" , cls .restore_database ,
1552+ "--user" , "dbadmin1" , "--no-password" ,
1553+ "admin" , "database" , "restore"
1554+ ],
1555+ input ,
1556+ additional_args
1557+ )
1558+
1559+
1560+ class TestClusterBackupRestore (BaseTestMultipleClusterBackupInFiles ):
1561+ def test_cluster_backup_restore (self ):
1562+ self .setup_sample_data ()
1563+
1564+ self .create_cluster_backup (expected_files = [
1565+ # cluster metadata
1566+ "permissions.pb" ,
1567+ "create_user.sql" ,
1568+ "create_group.sql" ,
1569+ "alter_group.sql" ,
1570+
1571+ # database metadata
1572+ "Root/db1/database.pb" ,
1573+ "Root/db1/permissions.pb" ,
1574+ "Root/db1/create_user.sql" ,
1575+ "Root/db1/create_group.sql" ,
1576+ "Root/db1/alter_group.sql" ,
1577+ ])
1578+
1579+ self .restore_cluster_backup ()
1580+
1581+ self .restore_cluster .wait_tenant_up (self .restore_database , self .cluster .config .default_clusteradmin )
1582+ self .restore_driver .wait (timeout = 10 )
1583+
1584+
1585+ class TestDatabaseBackupRestore (BaseTestMultipleClusterBackupInFiles ):
1586+ def test_database_backup_restore (self ):
1587+ self .setup_sample_data ()
1588+
1589+ self .create_cluster_backup (output = "cluster_backup" , expected_files = [
1590+ # cluster metadata
1591+ "permissions.pb" ,
1592+ "create_user.sql" ,
1593+ "create_group.sql" ,
1594+ "alter_group.sql" ,
1595+
1596+ # database metadata
1597+ "Root/db1/database.pb" ,
1598+ "Root/db1/permissions.pb" ,
1599+ "Root/db1/create_user.sql" ,
1600+ "Root/db1/create_group.sql" ,
1601+ "Root/db1/alter_group.sql" ,
1602+ ])
1603+
1604+ self .create_database_backup (output = "database_backup" , expected_files = [
1605+ # database metadata
1606+ "database.pb" ,
1607+ "permissions.pb" ,
1608+ "create_user.sql" ,
1609+ "create_group.sql" ,
1610+ "alter_group.sql" ,
1611+
1612+ # database table
1613+ "table/scheme.pb" ,
1614+ "table/permissions.pb" ,
1615+ "table/data_00.csv" ,
1616+ ])
1617+
1618+ self .restore_cluster_backup (input = "cluster_backup" )
1619+
1620+ self .restore_cluster .wait_tenant_up (self .restore_database , self .cluster .config .default_clusteradmin )
1621+ self .restore_driver .wait (timeout = 10 )
1622+
1623+ self .restore_database_backup (input = "database_backup" )
0 commit comments