data_storage.md•32.3 kB
# NetBrain MCP 数据存储设计
本文档详细描述NetBrain MCP系统的数据存储设计,包括实际的数据存储方案、数据模型、缓存策略和数据操作方法。
## 1. 数据存储架构概述
### 1.1 存储方案选择
NetBrain MCP系统采用**JSON文件存储**作为主要数据持久化方案,具有以下特点:
- **轻量级部署**:无需额外的数据库服务器
- **简单维护**:人类可读的JSON格式,便于调试和维护
- **快速启动**:无需数据库初始化和配置
- **跨平台兼容**:完全兼容Windows、Linux、macOS
- **备份简单**:数据文件可直接复制备份
### 1.2 数据存储结构
```
NetBrainMCP/
├── data/ # 主数据存储目录
│ ├── devices.json # 设备信息存储
│ └── credentials.json # 凭据信息存储(敏感数据)
├── resource_cache/ # 资源缓存目录
│ ├── device_*.json # 设备资源缓存
│ ├── topology_*.json # 拓扑资源缓存
│ └── scan_*.json # 扫描结果缓存
├── templates/ # 模板缓存目录
│ └── *.json # 模板元数据缓存
└── logs/ # 日志文件目录
├── netbrain_mcp.log # 应用主日志
├── device_connector.log # 设备连接日志
└── audit.log # 审计日志(安全增强)
```
## 2. 核心数据模型
### 2.1 网络设备模型
#### 2.1.1 NetworkDevice数据类
基于实际代码实现(`network_devices.py`第125-155行):
```python
@dataclass
class NetworkDevice:
"""网络设备模型"""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
name: str = ""
ip_address: str = ""
device_type: DeviceType = DeviceType.OTHER
vendor: DeviceVendor = DeviceVendor.OTHER
platform: str = "" # Scrapli平台类型(重要字段)
model: str = ""
os_version: str = ""
status: DeviceStatus = DeviceStatus.UNKNOWN
location: str = ""
credential_id: Optional[str] = None
description: str = ""
tags: List[str] = field(default_factory=list)
last_seen: Optional[datetime] = None
created_at: datetime = field(default_factory=datetime.now)
updated_at: datetime = field(default_factory=datetime.now)
custom_attributes: Dict[str, Any] = field(default_factory=dict)
```
#### 2.1.2 设备相关枚举
```python
class DeviceType(Enum):
"""网络设备类型枚举"""
ROUTER = "router"
SWITCH = "switch"
FIREWALL = "firewall"
LOAD_BALANCER = "load_balancer"
WIRELESS_CONTROLLER = "wireless_controller"
ACCESS_POINT = "access_point"
OTHER = "other"
class DeviceVendor(Enum):
"""网络设备厂商枚举"""
CISCO = "cisco"
HUAWEI = "huawei"
H3C = "h3c"
JUNIPER = "juniper"
ARISTA = "arista"
FORTINET = "fortinet"
CHECKPOINT = "checkpoint"
OTHER = "other"
class DeviceStatus(Enum):
"""设备状态枚举"""
ONLINE = "online"
OFFLINE = "offline"
UNREACHABLE = "unreachable"
MAINTENANCE = "maintenance"
UNKNOWN = "unknown"
```
#### 2.1.3 设备数据JSON示例
```json
{
"device-uuid-123": {
"id": "device-uuid-123",
"name": "Router-01",
"ip_address": "192.168.1.1",
"device_type": "router",
"vendor": "cisco",
"platform": "cisco_iosxe",
"model": "ISR4321",
"os_version": "16.09.04",
"status": "online",
"location": "数据中心机房A",
"credential_id": "cred-uuid-456",
"description": "核心路由器",
"tags": ["core", "production", "datacenter"],
"last_seen": "2024-01-15T10:30:45.123456",
"created_at": "2024-01-10T09:00:00.000000",
"updated_at": "2024-01-15T10:30:45.123456",
"custom_attributes": {
"management_vlan": "100",
"backup_schedule": "daily"
}
}
}
```
### 2.2 设备凭据模型
#### 2.2.1 DeviceCredential类
基于实际代码实现(`network_devices.py`第64-123行):
```python
class DeviceCredential:
"""设备凭据类"""
def __init__(self,
id: str = None,
name: str = "",
username: str = "",
password: str = "",
protocol: ConnectionProtocol = ConnectionProtocol.SSH,
port: int = None,
enable_password: str = None,
ssh_key_file: str = None):
self.id = id or str(uuid.uuid4())
self.name = name
self.username = username
self.password = password
self.protocol = protocol
self.port = port or (22 if protocol == ConnectionProtocol.SSH else 23)
self.enable_password = enable_password
self.ssh_key_file = ssh_key_file
```
#### 2.2.2 连接协议枚举
```python
class ConnectionProtocol(Enum):
"""连接协议枚举"""
SSH = "ssh"
TELNET = "telnet"
SNMP = "snmp"
HTTP = "http"
HTTPS = "https"
NETCONF = "netconf"
```
#### 2.2.3 凭据数据JSON示例
```json
{
"cred-uuid-456": {
"id": "cred-uuid-456",
"name": "思科设备SSH凭据",
"username": "admin",
"password": "cisco123",
"protocol": "ssh",
"port": 22,
"enable_password": "enable123",
"ssh_key_file": null
}
}
```
**⚠️ 安全注意**: 当前凭据以明文形式存储,生产环境中应实施加密存储。
## 3. 数据管理器实现
### 3.1 DeviceManager类
基于实际代码实现(`network_devices.py`第161-462行):
#### 3.1.1 初始化和配置
```python
class DeviceManager:
"""设备管理器,负责设备的创建、查询和管理"""
def __init__(self):
self.devices: Dict[str, NetworkDevice] = {}
self.credentials: Dict[str, DeviceCredential] = {}
self.data_dir = "data"
self.devices_file = os.path.join(self.data_dir, "devices.json")
self.credentials_file = os.path.join(self.data_dir, "credentials.json")
# 创建数据目录(如不存在)
os.makedirs(self.data_dir, exist_ok=True)
# 加载持久化数据
self.load_data()
logger.info("设备管理器初始化完成")
```
#### 3.1.2 数据持久化方法
**保存数据**:
```python
def save_data(self):
"""将设备和凭据数据保存到文件"""
# 保存设备数据
devices_data = {}
for device_id, device in self.devices.items():
devices_data[device_id] = device.to_dict()
with open(self.devices_file, 'w', encoding='utf-8') as f:
json.dump(devices_data, f, ensure_ascii=False, indent=2)
# 保存凭据数据
credentials_data = {}
for cred_id, credential in self.credentials.items():
cred_dict = {
"id": credential.id,
"name": credential.name,
"username": credential.username,
"password": credential.password, # 明文存储(待加密)
"protocol": credential.protocol.value,
"port": credential.port,
"enable_password": credential.enable_password,
"ssh_key_file": credential.ssh_key_file
}
credentials_data[cred_id] = cred_dict
with open(self.credentials_file, 'w', encoding='utf-8') as f:
json.dump(credentials_data, f, ensure_ascii=False, indent=2)
logger.info(f"数据已保存到: {self.data_dir}")
```
**加载数据**:
```python
def load_data(self):
"""从文件加载设备和凭据数据"""
# 加载设备数据
if os.path.exists(self.devices_file):
try:
with open(self.devices_file, 'r', encoding='utf-8') as f:
devices_data = json.load(f)
for device_id, device_dict in devices_data.items():
# 转换枚举类型
device_type = DeviceType(device_dict.get("device_type", "other"))
vendor = DeviceVendor(device_dict.get("vendor", "other"))
status = DeviceStatus(device_dict.get("status", "unknown"))
# 转换日期时间
created_at = datetime.fromisoformat(device_dict.get("created_at", datetime.now().isoformat()))
updated_at = datetime.fromisoformat(device_dict.get("updated_at", datetime.now().isoformat()))
last_seen = None
if device_dict.get("last_seen"):
last_seen = datetime.fromisoformat(device_dict.get("last_seen"))
# 创建设备对象
device = NetworkDevice(
id=device_id,
name=device_dict.get("name", ""),
ip_address=device_dict.get("ip_address", ""),
device_type=device_type,
vendor=vendor,
platform=device_dict.get("platform", ""),
model=device_dict.get("model", ""),
os_version=device_dict.get("os_version", ""),
status=status,
location=device_dict.get("location", ""),
credential_id=device_dict.get("credential_id"),
description=device_dict.get("description", ""),
tags=device_dict.get("tags", []),
last_seen=last_seen,
created_at=created_at,
updated_at=updated_at,
custom_attributes=device_dict.get("custom_attributes", {})
)
self.devices[device_id] = device
logger.info(f"从 {self.devices_file} 加载了 {len(self.devices)} 个设备")
except Exception as e:
logger.error(f"加载设备数据失败: {e}")
```
#### 3.1.3 CRUD操作
**添加设备**:
```python
def add_device(self, device: NetworkDevice) -> str:
"""添加设备"""
self.devices[device.id] = device
logger.info(f"设备添加成功: {device.name} ({device.ip_address})")
self.save_data() # 立即保存到文件
return device.id
```
**查询设备**:
```python
def get_device(self, device_id: str) -> Optional[NetworkDevice]:
"""获取设备"""
return self.devices.get(device_id)
def list_devices(self,
vendor: Optional[DeviceVendor] = None,
device_type: Optional[DeviceType] = None,
status: Optional[DeviceStatus] = None,
tag: Optional[str] = None) -> List[NetworkDevice]:
"""列出设备,支持过滤条件"""
devices = list(self.devices.values())
if vendor:
devices = [d for d in devices if d.vendor == vendor]
if device_type:
devices = [d for d in devices if d.device_type == device_type]
if status:
devices = [d for d in devices if d.status == status]
if tag:
devices = [d for d in devices if tag in d.tags]
return devices
```
**更新设备**:
```python
def update_device(self, device_id: str, **kwargs) -> Optional[NetworkDevice]:
"""更新设备信息"""
device = self.get_device(device_id)
if not device:
logger.warning(f"设备不存在: {device_id}")
return None
for key, value in kwargs.items():
if hasattr(device, key):
setattr(device, key, value)
device.updated_at = datetime.now()
logger.info(f"设备更新成功: {device.name} ({device.ip_address})")
self.save_data() # 保存更改
return device
```
**删除设备**:
```python
def delete_device(self, device_id: str) -> bool:
"""删除设备"""
if device_id in self.devices:
device = self.devices[device_id]
del self.devices[device_id]
logger.info(f"设备删除成功: {device.name} ({device.ip_address})")
self.save_data() # 保存更改
return True
return False
```
## 4. 缓存系统设计
### 4.1 资源缓存机制
基于实际代码实现(`mcp_resources.py`第56-180行):
#### 4.1.1 ResourceManager缓存实现
```python
class ResourceManager:
"""MCP资源管理器,负责资源注册和提供"""
def __init__(self):
self.resources = {}
self.resource_patterns = {}
self.resource_cache = {} # 内存缓存
self.cache_expiration = {} # 缓存过期时间
self.default_cache_ttl = 300 # 默认缓存5分钟
# 缓存目录
self.cache_dir = os.path.join(os.getcwd(), "resource_cache")
if not os.path.exists(self.cache_dir):
try:
os.makedirs(self.cache_dir)
logger.info(f"已创建资源缓存目录: {self.cache_dir}")
except Exception as e:
logger.warning(f"无法创建资源缓存目录: {str(e)}")
```
#### 4.1.2 双层缓存策略
**内存缓存**:
```python
async def get_resource(self, uri: str, use_cache: bool = True, cache_ttl: Optional[int] = None) -> Dict[str, Any]:
"""获取资源"""
# 检查内存缓存
if use_cache and uri in self.resource_cache:
# 检查缓存是否过期
if uri in self.cache_expiration and self.cache_expiration[uri] > datetime.datetime.now():
logger.info(f"从内存缓存获取资源: {uri}")
return self.resource_cache[uri]
else:
# 缓存过期,从缓存中删除
logger.info(f"资源缓存已过期: {uri}")
if uri in self.resource_cache:
del self.resource_cache[uri]
if uri in self.cache_expiration:
del self.cache_expiration[uri]
```
**文件缓存**:
```python
# 从文件缓存加载
if use_cache:
cache_file = self._get_cache_filename(uri)
if os.path.exists(cache_file):
try:
with open(cache_file, 'r', encoding='utf-8') as f:
cache_data = json.load(f)
# 检查缓存是否过期
if "expiration" in cache_data:
expiration = datetime.datetime.fromisoformat(cache_data["expiration"])
if expiration > datetime.datetime.now():
logger.info(f"从文件缓存加载资源: {uri}")
self.resource_cache[uri] = cache_data["data"]
self.cache_expiration[uri] = expiration
return cache_data["data"]
except Exception as e:
logger.warning(f"加载资源缓存文件失败: {str(e)}")
```
**缓存写入**:
```python
# 缓存结果
if use_cache:
self.resource_cache[uri] = result
ttl = cache_ttl or self.default_cache_ttl
expiration = datetime.datetime.now() + datetime.timedelta(seconds=ttl)
self.cache_expiration[uri] = expiration
# 保存到文件缓存
try:
cache_file = self._get_cache_filename(uri)
with open(cache_file, 'w', encoding='utf-8') as f:
json.dump({
"data": result,
"expiration": expiration.isoformat()
}, f, ensure_ascii=False, indent=2)
except Exception as e:
logger.warning(f"保存资源缓存文件失败: {str(e)}")
```
#### 4.1.3 缓存文件命名
```python
def _get_cache_filename(self, uri: str) -> str:
"""获取缓存文件名"""
# 将URI转换为文件名安全的字符串
safe_uri = uri.replace(':', '_').replace('/', '_').replace('.', '_').replace('\\', '_')
return os.path.join(self.cache_dir, f"{safe_uri}.json")
```
#### 4.1.4 缓存清理机制
```python
def clear_cache(self, uri: Optional[str] = None) -> bool:
"""清除资源缓存"""
try:
if uri:
if uri in self.resource_cache:
del self.resource_cache[uri]
if uri in self.cache_expiration:
del self.cache_expiration[uri]
# 删除文件缓存
cache_file = self._get_cache_filename(uri)
if os.path.exists(cache_file):
os.remove(cache_file)
logger.info(f"已清除资源缓存: {uri}")
else:
self.resource_cache.clear()
self.cache_expiration.clear()
# 删除所有缓存文件
if os.path.exists(self.cache_dir):
for filename in os.listdir(self.cache_dir):
if filename.endswith('.json'):
os.remove(os.path.join(self.cache_dir, filename))
logger.info("已清除所有资源缓存")
return True
except Exception as e:
logger.error(f"清除缓存失败: {str(e)}")
return False
```
### 4.2 缓存配置策略
#### 4.2.1 默认缓存时间(TTL)
```python
# 资源类型对应的缓存时间
CACHE_TTL_CONFIG = {
"device": 300, # 设备信息:5分钟
"config": 600, # 设备配置:10分钟
"topology": 900, # 拓扑信息:15分钟
"scan": 1800, # 扫描结果:30分钟
"system": 60, # 系统状态:1分钟
"credential": 3600 # 凭据信息:1小时
}
```
#### 4.2.2 缓存策略
- **即时缓存**:数据获取后立即缓存
- **延迟过期**:使用TTL控制缓存生命周期
- **主动清理**:提供手动清理接口
- **容量控制**:内存缓存大小限制(待实现)
## 5. 连接数据管理
### 5.1 连接状态存储
基于实际代码实现(`device_connector.py`第659-865行):
#### 5.1.1 ConnectionManager实现
```python
class ConnectionManager:
"""连接管理器"""
def __init__(self):
self.active_connections: Dict[str, DeviceConnector] = {}
# 连接键格式:"{device_id}:{credential_id}"
def _get_connection_key(self, device_id: str, credential_id: str) -> str:
"""生成连接键"""
return f"{device_id}:{credential_id}"
```
#### 5.1.2 连接状态数据结构
```python
# 活动连接信息示例
{
"device-123:cred-456": {
"device_connector": ScrapliConnector实例,
"device_info": {
"id": "device-123",
"name": "Router-01",
"ip_address": "192.168.1.1"
},
"credential_info": {
"id": "cred-456",
"username": "admin",
"protocol": "ssh"
},
"connection_status": {
"connected": True,
"last_activity": "2024-01-15T10:30:45",
"connection_time": "2024-01-15T10:25:30"
}
}
}
```
#### 5.1.3 连接查询接口
```python
def get_active_connections(self) -> List[Dict[str, Any]]:
"""获取活动连接列表"""
connections = []
for connection_key, connector in self.active_connections.items():
device_id, credential_id = connection_key.split(':', 1)
connection_info = {
"device_id": device_id,
"credential_id": credential_id,
"device_name": connector.device.name,
"device_ip": connector.device.ip_address,
"connected": connector.connected,
"last_activity": connector.last_activity.isoformat() if connector.last_activity else None,
"connection_key": connection_key
}
connections.append(connection_info)
return connections
```
## 6. 日志数据管理
### 6.1 日志存储结构
#### 6.1.1 日志文件分类
**应用主日志**(`logs/netbrain_mcp.log`):
```
2024-01-15 10:30:45,123 - netbrain_mcp - INFO - MCP服务器已启动
2024-01-15 10:31:02,456 - network_devices - INFO - 设备添加成功: Router-01 (192.168.1.1)
2024-01-15 10:31:15,789 - mcp_resources - INFO - 从缓存获取资源: device/device-123
```
**设备连接日志**(`logs/device_connector.log`):
```
2024-01-15 10:32:00,123 - device_connector - INFO - 正在通过Scrapli连接到设备: Router-01 (192.168.1.1)
2024-01-15 10:32:03,456 - device_connector - INFO - 已成功连接到设备: Router-01 (192.168.1.1)
2024-01-15 10:32:10,789 - device_connector - INFO - 命令 'show version' 在设备 Router-01 上执行成功
```
**审计日志**(`logs/audit.log`,安全增强功能):
```json
{"timestamp": "2024-01-15T10:30:45.123Z", "event_type": "device.added", "user_id": "admin", "resource": "device:123", "action": "add", "result": "success"}
{"timestamp": "2024-01-15T10:32:10.789Z", "event_type": "command.executed", "user_id": "admin", "resource": "device:123", "details": {"command": "show version"}}
```
#### 6.1.2 日志格式化
基于实际代码实现(所有模块的JsonFormatter):
```python
class JsonFormatter(logging.Formatter):
def __init__(self, fmt=None, datefmt=None, style='%'):
super().__init__(fmt, datefmt, style)
def format(self, record):
log_record = super().format(record)
return log_record.encode('utf-8', errors='replace').decode('utf-8')
# 配置日志格式
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(stream=sys.stdout)
]
)
# 设置所有处理器使用UTF-8编码格式化
for handler in logging.root.handlers:
if isinstance(handler, logging.StreamHandler):
handler.setFormatter(JsonFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
```
## 7. 数据备份和恢复
### 7.1 数据备份策略
#### 7.1.1 手动备份
```bash
# 备份核心数据文件
cp -r data/ backup/data_$(date +%Y%m%d_%H%M%S)/
# 备份缓存数据(可选)
cp -r resource_cache/ backup/cache_$(date +%Y%m%d_%H%M%S)/
# 备份日志文件
cp -r logs/ backup/logs_$(date +%Y%m%d_%H%M%S)/
```
#### 7.1.2 自动备份脚本
```python
# backup.py - 数据备份脚本
import os
import shutil
import datetime
from pathlib import Path
def backup_data():
"""执行数据备份"""
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
backup_dir = Path(f"backup/backup_{timestamp}")
backup_dir.mkdir(parents=True, exist_ok=True)
# 备份数据文件
if Path("data").exists():
shutil.copytree("data", backup_dir / "data")
print(f"数据文件已备份到: {backup_dir / 'data'}")
# 备份重要日志
if Path("logs").exists():
shutil.copytree("logs", backup_dir / "logs")
print(f"日志文件已备份到: {backup_dir / 'logs'}")
return backup_dir
if __name__ == "__main__":
backup_path = backup_data()
print(f"备份完成: {backup_path}")
```
### 7.2 数据恢复
#### 7.2.1 数据恢复流程
```python
def restore_data(backup_path: str):
"""从备份恢复数据"""
backup_dir = Path(backup_path)
if not backup_dir.exists():
raise ValueError(f"备份目录不存在: {backup_path}")
# 备份当前数据(安全措施)
current_backup = backup_data()
print(f"当前数据已备份到: {current_backup}")
try:
# 恢复数据文件
if (backup_dir / "data").exists():
if Path("data").exists():
shutil.rmtree("data")
shutil.copytree(backup_dir / "data", "data")
print("数据文件恢复完成")
# 重新加载数据到内存
device_manager.load_data()
print("数据已重新加载到内存")
except Exception as e:
print(f"恢复失败: {str(e)}")
raise
```
## 8. 性能优化
### 8.1 数据访问优化
#### 8.1.1 内存索引
```python
class OptimizedDeviceManager(DeviceManager):
"""优化的设备管理器"""
def __init__(self):
super().__init__()
self._ip_index = {} # IP地址索引
self._name_index = {} # 设备名称索引
self._vendor_index = {} # 厂商索引
self._build_indexes()
def _build_indexes(self):
"""构建索引"""
for device_id, device in self.devices.items():
# IP地址索引
self._ip_index[device.ip_address] = device_id
# 名称索引
self._name_index[device.name.lower()] = device_id
# 厂商索引
vendor = device.vendor.value
if vendor not in self._vendor_index:
self._vendor_index[vendor] = []
self._vendor_index[vendor].append(device_id)
def get_device_by_ip(self, ip_address: str) -> Optional[NetworkDevice]:
"""通过IP地址快速查找设备"""
device_id = self._ip_index.get(ip_address)
return self.devices.get(device_id) if device_id else None
```
#### 8.1.2 批量操作优化
```python
def bulk_add_devices(self, devices: List[NetworkDevice]) -> List[str]:
"""批量添加设备(减少I/O操作)"""
device_ids = []
for device in devices:
self.devices[device.id] = device
device_ids.append(device.id)
logger.info(f"设备添加到内存: {device.name}")
# 一次性保存所有更改
self.save_data()
logger.info(f"批量添加 {len(devices)} 个设备完成")
return device_ids
```
### 8.2 缓存优化
#### 8.2.1 预加载策略
```python
async def preload_common_resources(self):
"""预加载常用资源"""
common_resources = [
"system/status",
"credentials",
"topology/statistics"
]
for uri in common_resources:
try:
await self.get_resource(uri, use_cache=True)
logger.info(f"预加载资源: {uri}")
except Exception as e:
logger.warning(f"预加载资源失败: {uri}, {str(e)}")
```
#### 8.2.2 智能缓存清理
```python
def cleanup_expired_cache(self):
"""清理过期缓存"""
now = datetime.datetime.now()
expired_uris = []
for uri, expiration in self.cache_expiration.items():
if expiration <= now:
expired_uris.append(uri)
for uri in expired_uris:
self.clear_cache(uri)
logger.info(f"清理了 {len(expired_uris)} 个过期缓存项")
```
## 9. 数据迁移
### 9.1 版本升级迁移
#### 9.1.1 数据格式版本管理
```python
DATA_FORMAT_VERSION = "1.0"
def check_data_format_version():
"""检查数据格式版本"""
version_file = Path("data/version.json")
if not version_file.exists():
# 首次运行,创建版本文件
create_version_file()
return True
with open(version_file, 'r') as f:
version_data = json.load(f)
current_version = version_data.get("version", "0.0")
if current_version != DATA_FORMAT_VERSION:
logger.info(f"检测到数据格式升级: {current_version} -> {DATA_FORMAT_VERSION}")
migrate_data(current_version, DATA_FORMAT_VERSION)
update_version_file()
return True
```
#### 9.1.2 数据迁移处理
```python
def migrate_data(from_version: str, to_version: str):
"""执行数据迁移"""
logger.info(f"开始数据迁移: {from_version} -> {to_version}")
# 备份原始数据
backup_path = backup_data()
logger.info(f"原始数据已备份到: {backup_path}")
try:
if from_version == "0.9" and to_version == "1.0":
migrate_0_9_to_1_0()
# 添加其他版本迁移逻辑
logger.info("数据迁移完成")
except Exception as e:
logger.error(f"数据迁移失败: {str(e)}")
raise
def migrate_0_9_to_1_0():
"""0.9版本到1.0版本的迁移"""
# 示例:添加platform字段
for device in device_manager.devices.values():
if not hasattr(device, 'platform') or not device.platform:
# 根据vendor自动推断platform
if device.vendor == DeviceVendor.CISCO:
device.platform = "cisco_iosxe"
elif device.vendor == DeviceVendor.HUAWEI:
device.platform = "huawei_vrp"
# 添加其他厂商映射
# 保存迁移后的数据
device_manager.save_data()
```
## 10. 监控和维护
### 10.1 数据健康检查
```python
def health_check():
"""数据健康检查"""
issues = []
# 检查数据文件完整性
if not Path("data/devices.json").exists():
issues.append("设备数据文件缺失")
if not Path("data/credentials.json").exists():
issues.append("凭据数据文件缺失")
# 检查数据一致性
for device in device_manager.devices.values():
if device.credential_id and not device_manager.get_credential(device.credential_id):
issues.append(f"设备 {device.name} 引用的凭据不存在: {device.credential_id}")
# 检查缓存目录
if not Path("resource_cache").exists():
issues.append("资源缓存目录缺失")
if issues:
logger.warning(f"发现 {len(issues)} 个数据问题:")
for issue in issues:
logger.warning(f" - {issue}")
else:
logger.info("数据健康检查通过")
return len(issues) == 0
```
### 10.2 存储空间管理
```python
def get_storage_usage():
"""获取存储使用情况"""
def get_dir_size(path):
total = 0
for dirpath, dirnames, filenames in os.walk(path):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
if os.path.exists(filepath):
total += os.path.getsize(filepath)
return total
usage = {
"data": get_dir_size("data") if Path("data").exists() else 0,
"cache": get_dir_size("resource_cache") if Path("resource_cache").exists() else 0,
"logs": get_dir_size("logs") if Path("logs").exists() else 0,
"templates": get_dir_size("templates") if Path("templates").exists() else 0
}
total = sum(usage.values())
logger.info(f"存储使用情况 (总计: {total / 1024 / 1024:.2f} MB):")
for category, size in usage.items():
logger.info(f" {category}: {size / 1024 / 1024:.2f} MB")
return usage
```
## 11. 总结
NetBrain MCP的数据存储设计采用了轻量级、高效的JSON文件存储方案,具有以下特点:
### 11.1 设计优势
- **简单可靠**:JSON格式人类可读,便于维护和调试
- **无依赖性**:无需额外的数据库服务器
- **跨平台**:完全兼容各种操作系统
- **快速部署**:零配置即可使用
- **易于备份**:简单的文件复制即可备份
### 11.2 性能特性
- **双层缓存**:内存+文件双层缓存机制
- **智能过期**:基于TTL的缓存过期策略
- **批量操作**:支持批量数据操作以减少I/O
- **索引优化**:内存索引提高查询性能
### 11.3 扩展能力
- **版本迁移**:完整的数据格式升级迁移机制
- **健康检查**:数据完整性和一致性检查
- **监控告警**:存储使用情况监控
- **安全增强**:计划实施数据加密存储
这种数据存储设计很好地平衡了简单性、性能和可维护性,为NetBrain MCP系统提供了稳定可靠的数据持久化基础。