Netmiko và Scrapli đều là thư viện "screen scraping": mở phiên SSH tương tác, gửi lệnh CLI, đợi prompt rồi trả về text. Dùng khi thiết bị không có (hoặc bạn không muốn dùng) API có cấu trúc như NETCONF/gNMI. Cả hai lo phần khó: nhận diện prompt, tắt phân trang, vào/ra config mode.
Cách hoạt động
flowchart LR A["Script Python"] --> B{"Thư viện"} B -->|"Netmiko"| C["Paramiko"] B -->|"Scrapli"| D["system (OpenSSH) / paramiko / ssh2 / asyncssh"] C --> E[("Router")] D --> E E -->|"text output"| F["TextFSM / TTP / Genie"] F --> G["dict / list"]
So sánh
| Tiêu chí | Netmiko | Scrapli |
|---|---|---|
| Tác giả | Kirk Byers | Carl Montanari |
| Transport SSH | Paramiko | Chọn được: system (mặc định, gọi binary OpenSSH), paramiko, ssh2, asyncssh, telnet, asynctelnet |
| Số platform | Rất nhiều (hàng trăm device_type) |
5 core: cisco_iosxe, cisco_iosxr, cisco_nxos, arista_eos, juniper_junos; thêm qua scrapli_community |
| Async | Không (dùng thread để chạy song song) | Có AsyncScrapli với asyncssh / asynctelnet |
| Tốc độ | Đủ dùng, chậm hơn do chờ theo delay | Nhanh hơn, đọc prompt theo pattern thay vì sleep |
Dùng ~/.ssh/config (ProxyJump) |
Hỗ trợ qua ssh_config_file |
Transport system dùng OpenSSH nên ăn ~/.ssh/config tự nhiên |
| Parse output | use_textfsm=True, use_ttp, use_genie |
response.textfsm_parse_output(), ttp_parse_output(), genie_parse_output() |
| Commit IOS XR / Junos | Có method commit() |
Gửi commit như một lệnh trong send_configs |
| Hệ sinh thái | Nền của Nornir-netmiko, NAPALM (một số driver), nhiều script cũ | scrapli_netconf, scrapli_cfg (config replace/diff), nornir_scrapli |
Ví dụ ngắn
Netmiko
import os
from netmiko import ConnectHandler
dev = {
"device_type": "cisco_xr", # Junos: "juniper_junos"
"host": "198.51.100.11",
"username": os.environ["NET_USER"],
"password": os.environ["NET_PASS"],
}
with ConnectHandler(**dev) as conn:
print(conn.send_command("show ipv4 interface brief"))
conn.send_config_set(
["interface GigabitEthernet0/0/0/1", "description to-pe2-hcm"],
exit_config_mode=False,
)
conn.commit(comment="CHG-1234") # Junos: conn.commit(confirm=True, confirm_delay=5) rồi conn.commit()
conn.exit_config_mode()Scrapli
import os
from scrapli import Scrapli
dev = {
"host": "198.51.100.11",
"auth_username": os.environ["NET_USER"],
"auth_password": os.environ["NET_PASS"],
"auth_strict_key": False, # lab; production nên kiểm tra host key
"platform": "cisco_iosxr", # Junos: "juniper_junos"
}
with Scrapli(**dev) as conn:
r = conn.send_command("show ipv4 interface brief")
print(r.result, r.elapsed_time)
r = conn.send_configs([
"interface GigabitEthernet0/0/0/1",
"description to-pe2-hcm",
"commit comment CHG-1234",
])
if r.failed:
print("Có lệnh lỗi:", [x.channel_input for x in r if x.failed])Với IOS XR và Junos, nếu thoát config mode khi còn thay đổi chưa commit, thiết bị sẽ hỏi lại (XR: Uncommitted changes found, commit them before exiting(yes/no/cancel)?). Luôn commit hoặc abort/rollback 0 trước khi thoát để script không treo ở prompt đó.
Khi nào dùng
| Tình huống | Chọn |
|---|---|
| Script nhỏ, đội đã quen, nhiều vendor lạ (switch cũ, firewall, OLT...) | Netmiko |
| Cần chạy song song hàng trăm thiết bị, muốn asyncio | Scrapli (AsyncScrapli) |
Phải đi qua jumphost phức tạp theo ~/.ssh/config |
Scrapli transport system |
| Cần config replace có diff cho XR/Junos | scrapli_cfg, hoặc tốt hơn là NETCONF / PyEZ |
| Đã dùng Ansible | Không cần cả hai: network_cli của Ansible đã lo SSH |
| Cần dữ liệu có cấu trúc, ổn định giữa các release | Bỏ screen scraping, dùng NETCONF hoặc gNMI |