Tóm tắt: PyEZ (junos-eznc) chạy trên NETCONF over SSH (port 830). Dùng Device để kết nối và đọc dev.facts, dev.rpc.* để lấy dữ liệu vận hành, và Config để load/diff/commit. Quy trình an toàn: load → diff → commit_check → commit(confirm=N) → kiểm tra → commit() lần hai để xác nhận.
Luồng hoạt động
flowchart LR A["Device.open()"] --> B["Config(dev, mode=exclusive)"] B --> C["cu.load()"] C --> D["cu.diff()"] D --> E["cu.commit_check()"] E --> F["cu.commit(confirm=5)"] F --> G{"Kiểm tra OK?"} G -->|Có| H["cu.commit() xác nhận"] G -->|Không| I["không làm gì, tự rollback sau 5 phút"]
Cấu hình
Chuẩn bị
set system services netconf ssh
set system login user automation class super-user authentication ssh-ed25519 "ssh-ed25519 AAAA... automation"python3 -m pip install junos-eznc
export NET_USER=automation NET_PASS='***'Kết nối và facts
import os
from jnpr.junos import Device
creds = {"user": os.environ["NET_USER"], "passwd": os.environ["NET_PASS"]}
with Device(host="198.51.100.21", port=830, **creds) as dev:
dev.timeout = 60 # timeout RPC (giây), mặc định 30
f = dev.facts
print(f["hostname"], f["model"], f["version"], f["serialnumber"])Dùng SSH key thay mật khẩu: bỏ passwd, thêm ssh_private_key_file="~/.ssh/id_ed25519". Có ~/.ssh/config (ProxyJump...) thì truyền ssh_config="~/.ssh/config", xem SSH config và jumphost.
Gọi RPC vận hành
Tên RPC lấy bằng | display xml rpc trên CLI, đổi - thành _:
user@pe1> show interfaces terse ge-0/0/1 | display xml rpc
<rpc>
<get-interface-information>
<terse/>
<interface-name>ge-0/0/1</interface-name>
</get-interface-information>
</rpc>rsp = dev.rpc.get_interface_information(terse=True, interface_name="ge-0/0/1")
for ifl in rsp.findall(".//logical-interface"):
print(ifl.findtext("name").strip(), ifl.findtext("oper-status").strip())
# Lấy config dạng JSON (đã lọc)
cfg = dev.rpc.get_config(
filter_xml="<configuration><protocols><bgp/></protocols></configuration>",
options={"format": "json"},
)Load, diff, commit confirmed
import os
from jnpr.junos import Device
from jnpr.junos.utils.config import Config
from jnpr.junos.exception import ConfigLoadError, CommitError, LockError
creds = {"user": os.environ["NET_USER"], "passwd": os.environ["NET_PASS"]}
with Device(host="198.51.100.21", **creds) as dev:
try:
with Config(dev, mode="exclusive") as cu:
cu.load(path="bgp.set", format="set") # hoặc format="text" + merge=True
diff = cu.diff()
if not diff:
print("Không có thay đổi")
else:
print(diff)
cu.commit_check()
cu.commit(comment="CHG-1236 add peer", confirm=5)
# ... kiểm tra BGP lên bằng dev.rpc.get_bgp_summary_information() ...
cu.commit(comment="CHG-1236 confirm")
except LockError:
print("Config đang bị khoá bởi session khác")
except (ConfigLoadError, CommitError) as e:
print("Lỗi:", e)set protocols bgp group EBGP-PEER neighbor 203.0.113.1 peer-as 64501
set protocols bgp group EBGP-PEER neighbor 203.0.113.1 description to-transit-a
set protocols bgp group EBGP-PEER import TRANSIT-IN
set protocols bgp group EBGP-PEER export TRANSIT-OUT| Cách load | Ý nghĩa |
|---|---|
cu.load(path="x.set", format="set") |
Như load set |
cu.load(path="x.conf", format="text", merge=True) |
Như load merge |
cu.load(path="x.conf", format="text", overwrite=True) |
Như load override (thay toàn bộ config) |
cu.load(path="x.conf", format="text") |
Không merge/overwrite → load replace (theo tag replace:) |
cu.load(template_path="t.j2", template_vars={...}, format="set") |
Render Jinja2 rồi load |
cu.load("set system ntp server 192.0.2.123", format="set") |
Load chuỗi trực tiếp |
mode của Config: exclusive (khoá, tương đương configure exclusive), private (candidate riêng), dynamic, batch, ephemeral. Trên router nhiều người cùng thao tác, dùng exclusive hoặc private.
Rollback
with Config(dev, mode="exclusive") as cu:
cu.rollback(rb_id=1) # nạp lại config trước commit gần nhất
print(cu.diff())
cu.commit(comment="rollback 1")cu.rollback() (mặc định rb_id=0) là huỷ thay đổi chưa commit trong candidate. cu.rescue(action="reload") nạp lại rescue config.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
ConnectRefusedError |
Chưa bật system services netconf ssh hoặc port 830 bị filter |
Bật NETCONF, kiểm tra lo0 filter / mgmt ACL |
ConnectAuthError |
Sai user/mật khẩu hoặc key | Thử ssh -p 830 user@host -s netconf |
ConnectTimeoutError |
Không tới được host, sai port | Kiểm tra route mgmt, nc -vz host 830 |
RpcTimeoutError khi commit |
Commit lâu (config lớn, RE yếu) | Tăng dev.timeout = 300 |
LockError |
Có người đang configure exclusive / có thay đổi chưa commit |
status trên CLI, dùng mode="private" |
ConfigLoadError (syntax error) |
Sai cú pháp set hoặc sai hierarchy |
Thử dòng lệnh trực tiếp trên CLI trước |
| Commit confirmed tự rollback | Quên cu.commit() lần hai trong thời hạn |
Thêm bước xác nhận sau khi kiểm tra |
dev.facts thiếu khoá / chậm |
Facts tự gom khi open() |
Device(..., gather_facts=False) nếu không cần |
Tham khảo
- Junos PyEZ Developer Guide
- junos-eznc trên GitHub
- Junos CLI cheatsheet
- NETCONF với ncclient nếu cần XML thuần, nhiều vendor