115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
"""业务下发服务"""
|
|
from typing import Dict
|
|
from sqlalchemy.orm import Session
|
|
from app.services.ssh_service import SSHService
|
|
from app.models.device import ONUDevice, OLTDevice
|
|
import time
|
|
|
|
|
|
class ProvisionService:
|
|
"""业务下发服务"""
|
|
|
|
def __init__(self, db: Session):
|
|
self.db = db
|
|
|
|
def provision_device(self, device_id: int) -> Dict[str, any]:
|
|
"""
|
|
业务下发流程(参照下发业务流程.md):
|
|
1. system-view
|
|
2. interface Onu{port_id}
|
|
3. uni 1 vlan-mode trunk pvid 4094 2000 to 2000 3000 to 3010
|
|
4. port link-type trunk
|
|
5. undo port trunk permit vlan 1
|
|
6. port trunk permit vlan 2000 3000 to 3010 4094
|
|
7. save force
|
|
"""
|
|
device = self.db.query(ONUDevice).filter(ONUDevice.id == device_id).first()
|
|
if not device:
|
|
return {"success": False, "error": f"设备不存在: {device_id}"}
|
|
|
|
if not device.olt_id:
|
|
return {"success": False, "error": "设备未关联 OLT,请先进行扫描"}
|
|
|
|
olt = self.db.query(OLTDevice).filter(OLTDevice.id == device.olt_id).first()
|
|
if not olt:
|
|
return {"success": False, "error": "关联的 OLT 设备不存在"}
|
|
|
|
if not device.port_id:
|
|
return {"success": False, "error": "设备端口信息不完整,请先对 OLT 执行扫描"}
|
|
|
|
port_name = f"Onu{device.port_id}"
|
|
ssh = SSHService(olt.ip_address, olt.username, olt.password)
|
|
|
|
try:
|
|
ssh.connect()
|
|
|
|
def send_and_wait(cmd: str, expect: str, timeout: int = 15) -> str:
|
|
ssh.shell.send(cmd + "\n")
|
|
buf = ""
|
|
deadline = time.time() + timeout
|
|
while time.time() < deadline:
|
|
if ssh.shell.recv_ready():
|
|
buf += ssh.shell.recv(4096).decode("utf-8", errors="ignore")
|
|
if expect in buf:
|
|
return buf
|
|
else:
|
|
time.sleep(0.2)
|
|
return buf
|
|
|
|
# 进入系统视图
|
|
out = send_and_wait("system-view", "]")
|
|
if "]" not in out:
|
|
raise Exception("进入 system-view 失败")
|
|
|
|
# 进入端口
|
|
out = send_and_wait(f"interface {port_name}", "]")
|
|
if "]" not in out:
|
|
raise Exception(f"进入端口 {port_name} 失败")
|
|
|
|
# 配置 VLAN
|
|
send_and_wait("uni 1 vlan-mode trunk pvid 4094 2000 to 2000 3000 to 3010", "]")
|
|
send_and_wait("port link-type trunk", "]")
|
|
send_and_wait("undo port trunk permit vlan 1", "]")
|
|
send_and_wait("port trunk permit vlan 2000 3000 to 3010 4094", "]")
|
|
|
|
# 保存配置(等待 "successfully" 出现)
|
|
save_out = send_and_wait("save force", "successfully", timeout=30)
|
|
if "successfully" not in save_out:
|
|
raise Exception("save force 未确认成功,请检查 OLT 日志")
|
|
|
|
return {
|
|
"success": True,
|
|
"device_id": device_id,
|
|
"mac_address": device.mac_address,
|
|
"olt_ip": olt.ip_address,
|
|
"port": port_name,
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
"success": False,
|
|
"device_id": device_id,
|
|
"mac_address": device.mac_address,
|
|
"error": str(e),
|
|
}
|
|
finally:
|
|
ssh.close()
|
|
|
|
def batch_provision(self, device_ids: list) -> Dict[str, any]:
|
|
results = []
|
|
success_count = 0
|
|
fail_count = 0
|
|
for device_id in device_ids:
|
|
result = self.provision_device(device_id)
|
|
results.append(result)
|
|
if result.get("success"):
|
|
success_count += 1
|
|
else:
|
|
fail_count += 1
|
|
return {
|
|
"total": len(device_ids),
|
|
"success": success_count,
|
|
"failed": fail_count,
|
|
"results": results,
|
|
}
|