Nỗi ám ảnh gõ lệnh thủ công và các hướng tự động hóa mạng
Dân vận hành mạng chắc ai cũng từng trải qua cảnh này: 11 giờ đêm, mở hàng chục tab PuTTY. Mục tiêu chỉ là sửa một dòng access-list, đổi địa chỉ NTP server hay backup file cấu hình trên 50 con switch chi nhánh.
Làm thủ công vừa tốn sức vừa dễ trả giá đắt. Bạn chỉ cần gõ nhầm một octet IP, quên gõ write memory, hoặc rớt mạng giữa lúc terminal đang đẩy dở lệnh. Hậu quả là cả chi nhánh lập tức mất kết nối. Để thoát cảnh này, giới network thường chọn một trong 4 giải pháp sau:
- Script Bash kết hợp Expect hoặc Paramiko thuần: Mở session SSH trực tiếp và đẩy chuỗi ký tự thô vào CLI của thiết bị.
- Ansible Network: Quản trị theo hướng khai báo (declarative) bằng playbook YAML thông qua các collection chính hãng.
- Netmiko (Python): Thư viện chuyên dụng xây trên nền Paramiko, tối ưu hóa riêng cho CLI của hơn 100 hệ điều hành mạng phổ biến.
- RESTCONF / NETCONF (YANG Model): Giao tiếp qua API có cấu trúc với dữ liệu JSON/XML trên các dòng thiết bị đời mới.
Được và mất của từng phương án
Mỗi công cụ đều có đất diễn riêng. Tuy nhiên, độ phức tạp khi triển khai thực tế lại rất chênh lệch:
- Paramiko thuần:
- Ưu điểm: Rất nhẹ, không phụ thuộc nhiều thư viện ngoài.
- Nhược điểm: Xử lý terminal cực khổ. Bạn phải tự bắt chuỗi phân trang
--More--, nhét các đoạntime.sleep()để chờ buffer, rồi tự lọc prompt đặc thù (#,>,(config)#). Gặp lệnh trả về 5.000 dòng log là script rất dễ treo cứng.
- Ansible:
- Ưu điểm: Agentless, cực kỳ mạnh khi chuẩn hóa cấu hình diện rộng, có sẵn cơ chế idempotent (chỉ thay đổi khi có sự khác biệt).
- Nhược điểm: Khá cồng kềnh cho nhu cầu kiểm tra nhanh. Khi đụng các thiết bị chạy firmware cũ hoặc hãng ít tên tuổi, viết custom filter trong Ansible mệt hơn code Python rất nhiều.
- RESTCONF / NETCONF:
- Ưu điểm: Dữ liệu trả về chuẩn cấu trúc JSON/XML, không bao giờ sợ hãng đổi định dạng chữ trên màn hình CLI.
- Nhược điểm: Rào cản phần cứng lớn. Nhiều dòng switch doanh nghiệp đời cũ như Cisco Catalyst 2960 hay router ISR G2 không hỗ trợ, hoặc đòi hỏi license đắt đỏ.
- Netmiko:
- Ưu điểm: Giải quyết dứt điểm các phiền toái của Paramiko. Thư viện tự dò prompt, tự tắt phân trang màn hình (
terminal length 0), chuyển đổi mượt giữa user mode, enable mode và config mode. Danh sách hỗ trợ trải dài từ Cisco (IOS, NX-OS), Juniper (JunOS), MikroTik (RouterOS) tới Arista, Fortinet. - Nhược điểm: Bản chất vẫn là bóc tách chuỗi (text parsing). Nếu nhà sản xuất đổi cấu trúc hiển thị sau một bản update lớn, bạn phải sửa lại regex xử lý output.
- Ưu điểm: Giải quyết dứt điểm các phiền toái của Paramiko. Thư viện tự dò prompt, tự tắt phân trang màn hình (
Vì sao kỹ sư hệ thống chuộng Netmiko?
Tại Việt Nam, hiếm hạ tầng nào thuần một hãng. Trung tâm dữ liệu có thể chạy firewall Juniper SRX, switch lõi Cisco Catalyst, nhưng router biên chi nhánh lại là MikroTik CCR giá rẻ. Trong môi trường hỗn hợp này, Netmiko luôn là cứu cánh nhanh nhất.
Nó đủ nhẹ để nhúng vào một cron script định kỳ. Nó cũng đủ thông minh để xử lý timeout thay bạn. Quan trọng nhất, bạn giữ trọn quyền kiểm soát bằng Python: đọc file Excel chứa 200 địa chỉ IP, quét trạng thái cổng, rồi đẩy cảnh báo tức thì về Telegram.
Hướng dẫn thực hành Netmiko từng bước
1. Thiết lập môi trường ảo
Netmiko chạy tốt nhất trên Python 3.8 đến 3.12. Bạn hãy tạo một virtual environment riêng để tránh xung đột thư viện hệ thống:
# Tạo và kích hoạt môi trường ảo
python3 -m venv netauto-env
source netauto-env/bin/activate
# Cài đặt Netmiko bản mới nhất
pip install --upgrade netmiko
2. Chạy lệnh kiểm tra (Show Command) trên switch Cisco IOS
Hàm send_command() gửi lệnh xem thông tin và tự động chờ thiết bị đẩy đủ dữ liệu dựa theo prompt kết thúc:
import os
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoTimeoutException, NetmikoAuthenticationException
cisco_switch = {
'device_type': 'cisco_ios',
'host': '192.168.10.2',
'username': os.getenv('NET_USER', 'admin'),
'password': os.getenv('NET_PASS', 'StrongPassword123'),
'secret': os.getenv('NET_ENABLE', 'EnablePassword123'),
}
try:
print(f"Đang mở kết nối tới {cisco_switch['host']}...")
with ConnectHandler(**cisco_switch) as net_connect:
# Vào privileged EXEC mode
net_connect.enable()
# Gửi lệnh kiểm tra IP cổng
output = net_connect.send_command("show ip interface brief")
print("--- KẾT QUẢ TỪ THIẾT BỊ ---")
print(output)
except NetmikoTimeoutException:
print(f"Lỗi: Mất kết nối tới {cisco_switch['host']} (Timeout).")
except NetmikoAuthenticationException:
print(f"Lỗi: Sai tài khoản hoặc mật khẩu trên {cisco_switch['host']}.")
except Exception as e:
print(f"Lỗi phát sinh: {e}")
3. Đẩy cấu hình hàng loạt lên MikroTik RouterOS
CLI của MikroTik chia theo thư mục menu với prompt dạng [admin@MikroTik] >. Netmiko có sẵn driver mikrotik_routeros giúp gửi chuỗi lệnh chuẩn xác qua send_config_set():
from netmiko import ConnectHandler
mikrotik_router = {
'device_type': 'mikrotik_routeros',
'host': '192.168.88.1',
'username': 'admin',
'password': 'MikroTikSecretPassword',
'port': 22,
}
# Bộ lệnh cần áp dụng
config_commands = [
'/ip pool add name=pool-vpn ranges=172.16.100.10-172.16.100.50',
'/ip firewall filter add chain=input protocol=icmp action=accept comment="Allow Ping"',
'/system ntp client set enabled=yes servers=vn.pool.ntp.org'
]
with ConnectHandler(**mikrotik_router) as net_connect:
print("Đã kết nối MikroTik, đang đẩy danh sách cấu hình...")
output = net_connect.send_config_set(config_commands)
print(output)
print("Cấu hình MikroTik hoàn tất!")
4. Quản trị cấu hình an toàn trên Juniper JunOS
JunOS có cơ chế candidate configuration và commit rất chặt chẽ. Netmiko cung cấp các method riêng để kiểm tra lỗi cú pháp trước khi commit thật:
from netmiko import ConnectHandler
juniper_device = {
'device_type': 'juniper_junos',
'host': '10.0.0.1',
'username': 'noc_admin',
'password': 'JuniperPassword',
}
commands_to_apply = [
'set system services ssh root-login deny',
'set snmp location "Datacenter HaNoi Rack A1"'
]
with ConnectHandler(**juniper_device) as net_connect:
# Mở candidate config
net_connect.config_mode()
# Nạp các câu lệnh set
net_connect.send_config_set(commands_to_apply, exit_config_mode=False)
# Kiểm tra tính hợp lệ trước khi ghi đè
check_result = net_connect.commit(check=True)
print(f"Kết quả commit check: {check_result}")
# Nếu không lỗi, commit chính thức kèm lời ghi chú
net_connect.commit(comment="Automated security hardening via Netmiko")
net_connect.exit_config_mode()
print("Đã commit cấu hình an toàn lên Juniper!")
5. Ba mẹo sống còn khi chạy thực tế
Khi mở rộng script từ 1 lên 100 thiết bị, bạn cần chú ý các điểm sau:
- Đa luồng với Concurrent Futures: Đừng chạy vòng lặp
fortuần tự. 100 con switch chạy tuần tự mất chừng 20 phút. Nếu dùngconcurrent.futures.ThreadPoolExecutor(max_workers=20), tổng thời gian gom về dưới 1 phút. - Chủ động nâng timeout: Những câu lệnh nặng như
show tech-supporthoặc kiểm tra bảng route BGP hơn 900.000 prefix cần tăng thời gian chờ:send_command(cmd, read_timeout=90)để tránh đứt session bất ngờ. - Tận dụng TextFSM để bóc dữ liệu: Thay vì tự viết regex phức tạp, hãy truyền thêm tham số
use_textfsm=Truevàosend_command(). Netmiko sẽ tự chuyển bảng raw text thành danh sách Python dictionary rõ ràng.
