Skip to content

Commit

Permalink
PBM. Add test to check user restoration during PITR restore from sele…
Browse files Browse the repository at this point in the history
…ctive / full backup
  • Loading branch information
sandraromanchenko committed Dec 12, 2024
1 parent c359370 commit 56dbca6
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 1 deletion.
24 changes: 23 additions & 1 deletion pbm-functional/pytest/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,8 +565,22 @@ def enable_pitr(self,**kwargs):
time.sleep(1)

# disables PITR
def disable_pitr(self):
def disable_pitr(self, time_param=None):
n = testinfra.get_host("docker://" + self.pbm_cli)
if time_param:
target_time = int(datetime.fromisoformat(time_param).timestamp())
pitr_end = 0

while pitr_end < target_time:
result = n.check_output("pbm s -s backups -o json")
backups = json.loads(result)
if 'backups' in backups and 'pitrChunks' in backups['backups'] and 'pitrChunks' in backups['backups']['pitrChunks']:
pitr_end_cur = backups['backups']['pitrChunks']['pitrChunks'][0].get('range', {}).get('end', None)
if pitr_end_cur is not None:
pitr_end = pitr_end_cur
if pitr_end < target_time:
time.sleep(1)

result = n.check_output(
"pbm config --set pitr.enabled=false --out json")
Cluster.log("Disabling PITR: " + result)
Expand Down Expand Up @@ -625,6 +639,12 @@ def setup_authorization(host,uri):
'{"db":"admin","role":"clusterMonitor" },' +
'{"db":"admin","role":"restore" },' +
'{"db":"admin","role":"pbmAnyAction" }]});\'')
init_pbm_t_user = ('\'db.getSiblingDB("admin").createUser({user:"pbm_test",pwd:"pbmpass_test1","roles":[' +
'{"db":"admin","role":"readWrite","collection":""},' +
'{"db":"admin","role":"backup" },' +
'{"db":"admin","role":"clusterMonitor" },' +
'{"db":"admin","role":"restore" },' +
'{"db":"admin","role":"pbmAnyAction" }]});\'')
x509_pbm_user = ('\'db.getSiblingDB("$external").runCommand({createUser:"emailAddress=pbm@percona.com,CN=pbm,OU=client,O=Percona,L=SanFrancisco,ST=California,C=US","roles":[' +
'{"db":"admin","role":"readWrite","collection":""},' +
'{"db":"admin","role":"backup" },' +
Expand All @@ -645,6 +665,8 @@ def setup_authorization(host,uri):
'{"db":"admin","role":"pbmAnyAction" }]});\'')
logs = primary.check_output(
"mongo -u root -p root --quiet --eval " + init_pbm_user)
logs = primary.check_output(
"mongo -u root -p root --quiet --eval " + init_pbm_t_user)
#Cluster.log(logs)
if "authMechanism=MONGODB-X509" in uri:
logs = primary.check_output(
Expand Down
175 changes: 175 additions & 0 deletions pbm-functional/pytest/test_user_roles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import pytest
import pymongo
import bson
import testinfra
import time
import os
import docker
import threading

from datetime import datetime
from cluster import Cluster


@pytest.fixture(scope="package")
def docker_client():
return docker.from_env()


@pytest.fixture(scope="package")
def config():
return {
"mongos": "mongos",
"configserver": {
"_id": "rscfg",
"members": [{"host": "rscfg01"}, {"host": "rscfg02"}, {"host": "rscfg03"}],
},
"shards": [
{
"_id": "rs1",
"members": [{"host": "rs101"}, {"host": "rs102"}, {"host": "rs103"}],
},
{
"_id": "rs2",
"members": [{"host": "rs201"}, {"host": "rs202"}, {"host": "rs203"}],
},
],
}

@pytest.fixture(scope="package")
def pbm_mongodb_uri():
return 'mongodb://pbm_test:pbmpass_test1@127.0.0.1:27017/?authSource=admin'

@pytest.fixture(scope="package")
def newcluster(config, pbm_mongodb_uri):
return Cluster(config, pbm_mongodb_uri=pbm_mongodb_uri)

@pytest.fixture(scope="package")
def cluster(config):
return Cluster(config)


@pytest.fixture(scope="function")
def start_cluster(cluster, newcluster, request):
try:
cluster.destroy()
newcluster.destroy()
os.chmod("/backups", 0o777)
os.system("rm -rf /backups/*")
cluster.create()
cluster.setup_pbm()
yield True

finally:
if request.config.getoption("--verbose"):
cluster.get_logs()
try:
cluster.destroy(cleanup_backups=True)
except Exception as e:
newcluster.destroy(cleanup_backups=True)


def check_user(client, db_name, username, expected_roles):
try:
db_query = client.db.command({"usersInfo": {"user": username, "db": db_name}})
if db_query.get("ok") == 1 and len(db_query.get("users", [])) > 0:
roles = {role['role'] for role in db_query['users'][0]['roles']}
return roles == expected_roles
else:
return False
except pymongo.errors.OperationFailure as e:
return False

@pytest.mark.parametrize('restore_type',['part_bck','full_bck_part_rst_wo_user','full_bck_part_rst_user','full_bck'])
@pytest.mark.timeout(350, func_only=True)
def test_logical_PBM_T216(start_cluster, cluster, newcluster, restore_type):
cluster.check_pbm_status()
client = pymongo.MongoClient(cluster.connection)
client_shard = pymongo.MongoClient("mongodb://root:root@rs101,rs102,rs103/?replicaSet=rs1")
client.admin.command({"enableSharding": "test_db1", "primaryShard": "rs1"})
client.admin.command({"enableSharding": "test_db2", "primaryShard": "rs2"})
client.admin.command("shardCollection", "test_db1.test_coll11", key={"_id": "hashed"})
client.admin.command('updateUser', 'pbm_test', pwd='pbmpass_test2')
client.admin.command('createUser', 'admin_random_user1', pwd='test123', roles=[{'role':'readWrite','db':'admin'}, 'userAdminAnyDatabase', 'clusterAdmin'])
client_shard.admin.command('createUser', 'admin_random_user2', pwd='test123', roles=[{'role':'readWrite','db':'admin'}, 'userAdminAnyDatabase', 'clusterAdmin'])
client.test_db1.command('createUser', 'test_random_user1', pwd='test123', roles=[{'role':'readWrite','db':'test_db1'}, {'role':'clusterManager','db':'admin'}])
client_shard.test_db1.command('createUser', 'test_random_user2', pwd='test123', roles=[{'role':'readWrite','db':'test_db1'}, {'role':'clusterManager','db':'admin'}])
for i in range(10):
client["test_db1"]["test_coll11"].insert_one({"key": i, "data": i})
client["test_db2"]["test_coll21"].insert_one({"key": i, "data": i})
backup_full = cluster.make_backup("logical")
backup_partial = cluster.make_backup("logical --ns=test_db1.*,test_db2.*")
cluster.enable_pitr(pitr_extra_args="--set pitr.oplogSpanMin=0.5")
client.admin.command('createUser', 'admin_random_user3', pwd='test123', roles=[{'role':'readWrite','db':'admin'}, 'userAdminAnyDatabase', 'clusterAdmin'])
client_shard.admin.command('createUser', 'admin_random_user4', pwd='test123', roles=[{'role':'readWrite','db':'admin'}, 'userAdminAnyDatabase', 'clusterAdmin'])
client.test_db1.command('createUser', 'test_random_user3', pwd='test123', roles=[{'role':'readWrite','db':'test_db1'}, {'role':'clusterManager','db':'admin'}])
client_shard.test_db1.command('createUser', 'test_random_user4', pwd='test123', roles=[{'role':'readWrite','db':'test_db1'}, {'role':'clusterManager','db':'admin'}])
for i in range(10):
client["test_db1"]["test_coll11"].insert_one({"key": i+10, "data": i+10})
client["test_db2"]["test_coll21"].insert_one({"key": i+10, "data": i+10})
time.sleep(5)
pitr = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")
cluster.disable_pitr(pitr)
pitr = " --time=" + pitr
Cluster.log("Time for PITR is: " + pitr)
client.drop_database("test_db1")
client.drop_database("test_db2")
client.admin.command("dropUser", "admin_random_user1")
client_shard.admin.command("dropUser", "admin_random_user2")
client.admin.command("dropUser", "admin_random_user3")
client_shard.admin.command("dropUser", "admin_random_user4")
client.test_db1.command("dropUser", "test_random_user1")
client_shard.test_db1.command("dropUser", "test_random_user2")
client.test_db1.command("dropUser", "test_random_user3")
client_shard.test_db1.command("dropUser", "test_random_user4")

# restoring users and roles from selective backup is not supported
restore_commands = {
'part_bck': " --base-snapshot=" + backup_partial + pitr,
'full_bck_part_rst_wo_user': " --base-snapshot=" + backup_full + pitr + " --ns=test_db1.*,test_db2.*",
'full_bck_part_rst_user': " --base-snapshot=" + backup_full + pitr + " --ns=test_db1.*,test_db2.* --with-users-and-roles",
'full_bck': " --base-snapshot=" + backup_full + pitr
}

# re-create cluster with new PBM user for connection to check that restore and connection to DB are OK
# despite the same user with different password is present in backup
if restore_type == 'full_bck':
cluster.destroy()
newcluster.create()
newcluster.setup_pbm()
newcluster.check_pbm_status()
newcluster.make_restore(restore_commands.get(restore_type), check_pbm_status=True)
else:
cluster.make_restore(restore_commands.get(restore_type), check_pbm_status=True)

assert client["test_db1"]["test_coll11"].count_documents({}) == 20
assert client["test_db1"].command("collstats", "test_coll11").get("sharded", False)
assert client["test_db2"]["test_coll21"].count_documents({}) == 20
assert client["test_db2"].command("collstats", "test_coll21").get("sharded", True) is False

assert check_user(client, "admin", "admin_random_user1", {'readWrite', 'userAdminAnyDatabase', 'clusterAdmin'}) == \
(restore_type == 'full_bck'), \
f"Failed for {restore_type}: admin_random_user1 role mismatch"
assert check_user(client_shard, "admin", "admin_random_user2", {'readWrite', 'userAdminAnyDatabase', 'clusterAdmin'}) == \
(restore_type == 'full_bck'), \
f"Failed for {restore_type}: admin_random_user2 role mismatch"
assert check_user(client, "admin", "admin_random_user3", {'readWrite', 'userAdminAnyDatabase', 'clusterAdmin'}) == \
(restore_type == 'full_bck'), \
f"Failed for {restore_type}: admin_random_user3 role mismatch"
assert check_user(client_shard, "admin", "admin_random_user4", {'readWrite', 'userAdminAnyDatabase', 'clusterAdmin'}) == \
(restore_type == 'full_bck'), \
f"Failed for {restore_type}: admin_random_user4 role mismatch"
assert check_user(client, "test_db1", "test_random_user1", {'readWrite', 'clusterManager'}) == (restore_type not in \
['part_bck','full_bck_part_rst_wo_user']), \
f"Failed for {restore_type}: test_random_user1 role mismatch"
assert check_user(client_shard, "test_db1", "test_random_user2", {'readWrite', 'clusterManager'}) == (restore_type not in \
['part_bck','full_bck_part_rst_wo_user']), \
f"Failed for {restore_type}: test_random_user2 role mismatch"
# current limitation: option with-users-and-roles doesn't work with PITR
assert check_user(client, "test_db1", "test_random_user3", {'readWrite', 'clusterManager'}) == (restore_type not in \
['part_bck','full_bck_part_rst_wo_user', 'full_bck_part_rst_user']), \
f"Failed for {restore_type}: test_random_user3 role mismatch"
assert check_user(client_shard, "test_db1", "test_random_user4", {'readWrite', 'clusterManager'}) == (restore_type not in \
['part_bck','full_bck_part_rst_wo_user', 'full_bck_part_rst_user']), \
f"Failed for {restore_type}: test_random_user4 role mismatch"
Cluster.log("Finished successfully")

0 comments on commit 56dbca6

Please sign in to comment.