"""业务下发服务""" 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, }