背景
公司计划对MongoDB进行大版本升级,(4.0 ===》7.0) 因版本跨度比较大,所以不支持在原实例支持进行。因此针对这一场景,制定了先迁移数据,再同步账号这一升级方案。
迁移步骤
- 使用阿里云DTS同步MongoDB数据库结构及数据
- 使用python导出源实例数据库账号及关联的角色信息
- 使用python批量在目标实例创建账号及关联角色信息(密码需新建或从配置文件中找到原账号密码)
导出源实例账号及关联角色
import pymongo
import pandas as pd
# 连接源 MongoDB 实例
def connect_to_source_mongodb(host, port, username, password):
client = pymongo.MongoClient(host, port, username=username, password=password)
return client
# 查询源 MongoDB 实例下所有数据库的账号及对应的角色
def query_accounts_and_roles(source_client):
accounts_and_roles = {}
for db_name in source_client.list_database_names():
db = source_client[db_name]
users = []
for user in db['system.users'].find({}, {'_id': 0}):
users.append({'user': user['user'], 'roles': user.get('roles', [])})
accounts_and_roles[db_name] = users
return accounts_and_roles
# 导出数据到 Excel 表格
def export_to_excel(accounts_and_roles, filename):
writer = pd.ExcelWriter(filename)
for db_name, users in accounts_and_roles.items():
df = pd.DataFrame(users)
df.to_excel(writer, sheet_name=db_name, index=False)
writer.save()
# 主函数
def main():
# 源 MongoDB 连接信息
source_host = 'source_host'
source_port = 27017
source_username = 'source_username'
source_password = 'source_password'
# 连接源 MongoDB 实例
source_client = connect_to_source_mongodb(source_host, source_port, source_username, source_password)
# 查询源实例下所有数据库的账号及对应的角色
accounts_and_roles = query_accounts_and_roles(source_client)
# 导出数据到 Excel 表格
export_to_excel(accounts_and_roles, 'mongodb_accounts_and_roles.xlsx')
print("Export completed successfully.")
if __name__ == "__main__":
main()
在目标实例创建账号及关联角色
创建账号和给账号授权时需按照下面的格式进行创建,这样创建账号和角色的结构是以db为维度创建的,如果不以db为维度创建账号和授权,默认所有的账号都会创建在admin db下
import string
import random
from pymongo import MongoClient
client = MongoClient("mongodb://<username>:<password>@<mongodb_server>")
users = [
{
'username': 'xxxxxxxx',
'password': 'xxxxxxxx',
'db_roles': [
{'db': 'databasename', 'roles': [{'role': 'readWrite', 'db': 'databasename'}]},
{'db': 'databasename', 'roles': [{'role': 'read', 'db': 'databasename'}]},
{'db': 'databasename', 'roles': [{'role': 'read', 'db': 'databasename'}]},
],
},
{
'username': 'xxxxxxxx',
'password': 'xxxxxxxx',
'db_roles': [
{'db': 'databasename', 'roles': [{'role': 'readWrite', 'db': 'databasename'}]},
{'db': 'databasename', 'roles': [{'role': 'userAdmin', 'db': 'databasename'}]},
{'db': 'databasename', 'roles': [{'role': 'dbAdmin', 'db': 'databasename'}]},
{'db': 'databasename', 'roles': [{'role': 'readWrite', 'db': 'databasename'}]},
{'db': 'databasename', 'roles': [{'role': 'userAdmin', 'db': 'databasename'}]},
{'db': 'databasename', 'roles': [{'role': 'dbAdmin', 'db': 'databasename'}]},
],
},
]
# 创建随机密码
def generate_random_password(length=12):
characters = string.ascii_letters + string.digits + '*$#@!'
return ''.join(random.choice(characters) for _ in range(length))
def create_users(users):
for user_data in users:
# 获取用户信息
username = user_data['username']
password = generate_random_password()
db_roles = user_data['db_roles']
# 遍历每个数据库及其角色
for db_role in db_roles:
db_name = db_role['db']
roles = db_role['roles']
db = client[db_name]
# password = generate_random_password
# 创建用户
db.command("createUser", username, pwd=password, roles=roles)
print(f"Created user '{username}',password:{password} with roles '{roles}' in database '{db_name}'")
create_users(users)
client.close()