你好。最近我遇到了控制 TP-Link TL-SG2218 的问题。它在供应商固件上嵌入了 SSH CLI。使用标准控制台 linux 控制台 SSH 客户端 CLI 工作起来非常完美。这是我正在做的示例(我正在启用端口 10)
unit-1@unit1:~$ ssh [email protected]
[email protected]'s password:
TL-SG3428>enable
TL-SG3428#configure
TL-SG3428(config)#interface gigabitEthernet 1/0/10
TL-SG3428(config-if)#no shutdown
TL-SG3428(config-if)#exit
TL-SG3428(config)#exit
TL-SG3428#copy running-config startup-config
Start to save user config as the Next Startup Config file......
Saving user config OK!
TL-SG3428#exit
TL-SG3428>exit
Connection to 192.168.21.79 closed.
unit-1@unit1:~$
所以,工作真的很快而且完美
我需要做同样的事情,但是来自Python代码 我尝试过的:
使用标准 SSH 库(paramiko)
ssh = paramiko.SSHClient()
ssh.connect(ip, username=login, password=password, auth_timeout=20,
channel_timeout=20)
ssh.exec_command(command)
使用标准 exec_command 时出现 EOF 错误方法
使用paramiko,但实现交互式shell(使用通道)
ssh = paramiko.SSHClient()
ssh.connect(ip, username=login, password=password, auth_timeout=20,
channel_timeout=20)
channel = ssh.invoke_shell()
self.channel.send(command.encode("UTF-8"))
buff = ''
while "#" not in buff and ">" not in buff:
resp = self.channel.recv(4096)
buff += resp.decode("UTF-8")
print(buff)
print(buff)
陷入无限循环 如果我删除 while 循环来读取响应,并且只是通过小停顿传递命令,那么这是行不通的
我找到了这个Python库:netmiko 使用这段代码我终于能够正确执行命令
from netmiko import ConnectHandler
switch = {
'device_type': 'tplink_jetstream',
'host': ip,
'username': login,
'password': password
}
net_connect = ConnectHandler(**switch)
net_connect.send_command(command)
但我发现,当我运行完整场景时,netmiko 在大约 50% 的情况下工作 在另外 50% 的情况下,我总是会遇到这个异常(绝对随机,在随机命令之后)
[EXECUTING]enable
Already in admin level.
[EXECUTING]configure
TL-SG3428#configure
[EXECUTING]interface gigabitEthernet 1/0/10
INFO: 172.22.0.1:55758 - "POST /disable_switch HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 401, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 70, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 756, in __call__
await self.middleware_stack(scope, receive, send)
File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 776, in app
await route.handle(scope, receive, send)
File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 297, in handle
await self.app(scope, receive, send)
File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 77, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 72, in app
response = await func(request)
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/contextlib.py", line 222, in __aexit__
await self.gen.athrow(typ, value, traceback)
File "/usr/local/lib/python3.11/site-packages/fastapi/concurrency.py", line 35, in contextmanager_in_threadpool
raise e
netmiko.exceptions.ReadTimeout:
Pattern not detected: 'TL\\-SG3428\\(config\\)\\#' in output.
Things you might try to fix this:
1. Explicitly set your pattern using the expect_string argument.
2. Increase the read_timeout to a larger value.
You can also look at the Netmiko session_log or debug log for more information.
我真的快没精神了 你有什么建议? 我想到两个办法
尝试使用 Pexpect Lib(
Pexpect 是一个 Python 模块,允许生成子应用程序,然后进行控制,并响应输出中的预期模式。
import pexpect
# Start the SSH connection to the switch
child = pexpect.spawn('ssh [email protected]')
# Wait for the password prompt and send the password
child.expect("password:")
child.sendline('your_password_here') # Replace 'your_password_here' with the correct password
# Wait for the switch prompt
child.expect('TL-SG3428>')
# Send the 'enable' command
child.sendline('enable')
# Wait for the privileged mode prompt
child.expect('TL-SG3428#')
# Send the 'configure' command
child.sendline('configure')
# Wait for the global configuration prompt
child.expect('TL-SG3428\(config\)#')
# Send the command to enter the specified interface
child.sendline('interface gigabitEthernet 1/0/10')
# Wait for the interface configuration prompt
child.expect('TL-SG3428\(config-if\)#')
# Send the 'no shutdown' command
child.sendline('no shutdown')
# Exit interface configuration mode
child.sendline('exit')
# Wait for the global configuration prompt
child.expect('TL-SG3428\(config\)#')
# Exit global configuration mode
child.sendline('exit')
# Wait for the privileged mode prompt
child.expect('TL-SG3428#')
# Send the command to save the configuration
child.sendline('copy running-config startup-config')
# Wait for the save confirmation message
child.expect('Saving user config OK!')
# Exit privileged mode
child.sendline('exit')
# Exit EXEC mode
child.expect('TL-SG3428>')
# Close the SSH session
child.sendline('exit')
# Wait for the connection to close
child.expect(pexpect.EOF)
# Print the complete session output
print(child.before.decode('utf-8'))