如何在多Python文件项目中复用startup.py的已建立网络设备连接
你遇到的核心问题是对Python模块导入机制和进程隔离的误解:当你把startup.py作为独立脚本运行时,它会在自己的Python进程里建立连接并持续运行;而当其他Python文件import startup时,是在另一个独立的Python进程中加载startup.py的代码——两个进程的内存完全隔离,你根本无法直接获取到已运行的startup.py进程里的连接。
另外,即使在同一个进程内导入,当前你的代码结构也有问题:validate_connections_to_leaves()的调用被放在if __name__ == '__main__':块中,这意味着只有当startup.py作为主脚本运行时才会建立连接,其他模块导入它时不会执行这段代码,自然也拿不到连接。
下面针对两种常见场景给出具体解决方案:
场景1:所有操作在同一个Python进程内完成
如果你的所有脚本都可以在同一个进程中运行(不需要startup.py单独做守护进程),用单例模式管理连接是最简单高效的方式,确保只建立一次连接,其他模块导入时直接复用:
修改startup.py如下:
# startup.py import yaml_utils import junos_utils import log import pprint # 全局变量存储连接,仅初始化一次 _leaves_connections = None def get_leaves_connections(): global _leaves_connections if _leaves_connections is None: # 只在第一次调用时建立连接 _leaves_connections = validate_connections_to_leaves() return _leaves_connections def validate_connections_to_leaves(): # 注意:这里需要确保topology和debug变量已定义 leaves = yaml_utils.load_yaml_file_from_directory("inventory", topology)["fabric_leaves"] leaves_connections = [] for leaf in leaves: leaf_ip = leaf["ansible_host"] leaf_user = leaf["ansible_user"] leaf_pass = leaf["ansible_pass"] leaf_cnx = junos_utils.open_fabric_connection(host=leaf_ip, user=leaf_user, password=leaf_pass) if leaf_cnx: leaves_connections.append(leaf_cnx) else: log.script_logger(severity="ERROR", message="Unable to connect to Leaf", data=leaf_ip, debug=debug, indent=0) return leaves_connections if __name__ == '__main__': # 测试或作为主入口运行 connections = get_leaves_connections() pprint(connections) # 若需保持进程运行,可在此添加监听逻辑 while True: time.sleep(10)
然后在其他Python文件中,这样复用连接:
# other_script.py import startup # 获取已建立的连接,不会重复建立 connections = startup.get_leaves_connections() # 使用connections执行后续操作,比如获取配置、发送命令等
这种方式下,无论在同一个进程中多少次调用get_leaves_connections(),只会建立一次连接,完美实现复用。
场景2:必须跨进程共享连接(startup.py单独作为守护进程)
如果业务要求startup.py作为独立守护进程运行,其他脚本在不同进程中调用,那么需要用**进程间通信(IPC)**的方式间接使用连接——网络连接无法直接跨进程传递,通常的做法是把startup.py做成一个服务,其他脚本通过接口请求让它执行操作:
比如用FastAPI做一个简单的API服务:
# startup.py from fastapi import FastAPI import yaml_utils import junos_utils import log import uvicorn app = FastAPI() _leaves_connections = None def init_connections(): global _leaves_connections # 注意:确保topology和debug变量已定义 leaves = yaml_utils.load_yaml_file_from_directory("inventory", topology)["fabric_leaves"] leaves_connections = [] for leaf in leaves: leaf_ip = leaf["ansible_host"] leaf_user = leaf["ansible_user"] leaf_pass = leaf["ansible_pass"] leaf_cnx = junos_utils.open_fabric_connection(host=leaf_ip, user=leaf_user, password=leaf_pass) if leaf_cnx: leaves_connections.append(leaf_cnx) else: log.script_logger(severity="ERROR", message="Unable to connect to Leaf", data=leaf_ip, debug=debug, indent=0) _leaves_connections = leaves_connections # 示例接口:获取指定Leaf的配置 @app.get("/leaf/{leaf_ip}/config") def get_leaf_config(leaf_ip: str): for conn in _leaves_connections: # 假设连接对象有host属性存储IP,根据实际情况调整 if conn.host == leaf_ip: config = conn.get_config() # 假设junos_utils提供获取配置的方法 return {"status": "success", "config": config} return {"status": "error", "message": f"Leaf {leaf_ip} not found or disconnected"} if __name__ == '__main__': init_connections() # 启动服务,监听本地8000端口 uvicorn.run(app, host="127.0.0.1", port=8000)
其他Python文件通过HTTP请求调用服务:
# other_script.py import requests response = requests.get("http://127.0.0.1:8000/leaf/192.168.1.1/config") if response.status_code == 200: config_data = response.json()["config"] # 处理配置数据 else: print(f"请求失败:{response.json()['message']}")
这种方式下,startup.py作为守护进程维护所有连接,其他脚本通过API请求间接使用连接,避免了重复建立连接的问题。
内容的提问来源于stack exchange,提问作者Basim Aly

