Thursday, November 21, 2024

[Zabbix] Hướng dẫn sử dụng Type Dependent item trong Zabbix để xử lý dữ liệu Json

-

Trong Zabbix, một “Dependent Item” (hay còn gọi là “Item phụ thuộc”) là một item (mục) được tạo ra để lấy dữ liệu từ một item khác trong Zabbix. Khi một item phụ thuộc được tạo, nó sẽ liên kết với một item gốc và sử dụng giá trị từ item gốc để tính toán hoặc hiển thị dữ liệu.

Ví dụ, nếu bạn muốn theo dõi tài nguyên CPU của một máy chủ, bạn có thể tạo một item phụ thuộc để tính toán tỉ lệ sử dụng CPU của máy chủ đó. Item phụ thuộc sẽ liên kết với item CPU gốc và sử dụng giá trị của item CPU để tính toán tỉ lệ sử dụng CPU.

Item phụ thuộc là một tính năng hữu ích trong Zabbix để giảm thiểu số lượng item cần được tạo ra và giúp cho quá trình giám sát trở nên dễ dàng hơn.

Đầu tiên chúng ta sẽ code 1 đoạn ngắn python để lấy dữ liệu dạng json trên thiết bị Nexus 3064 nhé, nội dung mình lấy làm ví dụ là tên và trạng thái các interface có trong thiết bị và xuất chúng ra dữ liệu dạng json. File code mình sẽ để theo đường dẫn như vậy /usr/local/bin/interface_status.py.

#!/usr/bin/python3
import subprocess, json

get_name = subprocess.check_output("""snmpwalk -v3 -u demo -l authPriv -a MD5 -A 123abcxyz -x DES -X 123abcxyz 103.15.49.2 1.3.6.1.2.1.2.2.1.2""", shell=True).decode('utf-8').strip('\n').split('\n')
get_status = subprocess.check_output("""snmpwalk -v3 -u demo -l authPriv -a MD5 -A 123abcxyz -x DES -X 123abcxyz 103.15.49.2 1.3.6.1.2.1.2.2.1.8""", shell=True).decode('utf-8"').strip('\n').split('\n')

list_interface_status = []

for x in get_name:
    interface_name = x.split(':')[-1].strip().strip('"')
    oid_interface_name = x.split()[0].split('.')[10]
    for y in get_status:
        interface_status = y.split('INTEGER:')[-1]
        oid_interface_status = y.split(' = INTEGER: ')[0].split('.')[10]
        if int(interface_status) == int(2):
            status = 'Down'
        else:
            status = 'Up'
        if oid_interface_name == oid_interface_status:
            dict_interface_status = {
                interface_name: status
            }
            list_interface_status.append(dict_interface_status)

print(json.dumps(list_interface_status))

Lưu ý: Bạn không cần phải hiểu đoạn code trên, chỉ cần dữ liệu đầu ra của bạn có định dạng json là được.

Hãy phân quyền thực thi cho nó bằng lệnh.

chmod +x /usr/local/bin/interface_status.py

Và đây là kết quả khi ta chạy python3 /usr/local/bin/interface_status.py.

[{"mgmt0": "Down"}, {"Vlan1": "Down"}, {"Vlan2": "Up"}, {"Vlan4": "Up"}, {"Vlan5": "Up"}, {"Vlan6": "Up"}, {"Vlan7": "Up"}, {"Vlan8": "Up"}, {"Vlan9": "Up"}, {"Vlan20": "Up"}, {"Vlan21": "Up"}, {"Vlan31": "Up"}, {"Vlan32": "Up"}, {"Vlan33": "Up"}, {"Vlan34": "Up"}, {"Vlan35": "Up"}, {"Vlan36": "Up"}, {"Vlan37": "Up"}, {"Vlan38": "Up"}, {"Vlan39": "Up"}, {"Vlan47": "Up"}, {"Vlan99": "Up"}, {"Vlan100": "Up"}, {"Vlan101": "Up"}, {"Vlan102": "Up"}, {"Vlan103": "Up"}, {"Vlan150": "Up"}, {"port-channel1": "Up"}, {"port-channel2": "Up"}, {"port-channel22": "Down"}, {"port-channel24": "Down"}, {"port-channel26": "Down"}, {"port-channel28": "Down"}, {"port-channel30": "Down"}, {"port-channel32": "Down"}, {"port-channel34": "Down"}, {"port-channel36": "Down"}, {"port-channel45": "Down"}, {"port-channel46": "Up"}, {"port-channel51": "Up"}, {"port-channel52": "Up"}, {"port-channel99": "Down"}, {"port-channel100": "Up"}, {"Ethernet1/1": "Down"}, {"Ethernet1/2": "Down"}, {"Ethernet1/3": "Down"}, {"Ethernet1/4": "Down"}, {"Ethernet1/5": "Down"}, {"Ethernet1/6": "Down"}, {"Ethernet1/7": "Up"}, {"Ethernet1/8": "Down"}, {"Ethernet1/9": "Down"}, {"Ethernet1/10": "Down"}, {"Ethernet1/11": "Up"}, {"Ethernet1/12": "Down"}, {"Ethernet1/13": "Down"}, {"Ethernet1/14": "Down"}, {"Ethernet1/15": "Down"}, {"Ethernet1/16": "Down"}, {"Ethernet1/17": "Down"}, {"Ethernet1/18": "Down"}, {"Ethernet1/19": "Up"}, {"Ethernet1/20": "Down"}, {"Ethernet1/21": "Down"}, {"Ethernet1/22": "Down"}, {"Ethernet1/23": "Down"}, {"Ethernet1/24": "Down"}, {"Ethernet1/25": "Down"}, {"Ethernet1/26": "Down"}, {"Ethernet1/27": "Down"}, {"Ethernet1/28": "Down"}, {"Ethernet1/29": "Down"}, {"Ethernet1/30": "Up"}, {"Ethernet1/31": "Down"}, {"Ethernet1/32": "Down"}, {"Ethernet1/33": "Up"}, {"Ethernet1/34": "Down"}, {"Ethernet1/35": "Up"}, {"Ethernet1/36": "Down"}, {"Ethernet1/37": "Up"}, {"Ethernet1/38": "Down"}, {"Ethernet1/39": "Up"}, {"Ethernet1/40": "Up"}, {"Ethernet1/41": "Up"}, {"Ethernet1/42": "Down"}, {"Ethernet1/43": "Up"}, {"Ethernet1/44": "Up"}, {"Ethernet1/45": "Down"}, {"Ethernet1/46": "Up"}, {"Ethernet1/47": "Up"}, {"Ethernet1/48": "Up"}, {"Ethernet1/49": "Up"}, {"Ethernet1/50": "Up"}, {"Ethernet1/51": "Down"}, {"Ethernet1/52": "Up"}]

Ví dụ nội dung trong file /etc/zabbix/zabbix_agentd.d/userparameter.conf, mình sử dụng key cisco.interface.status để chạy file /usr/local/bin/interface_status.py

UserParameter=cisco.interface.status,interface_status.py

Tiếp theo chúng ta tạo 1 item mới, mình sử dụng server Linux có cài đặt Zabbix Agent để chạy script trên. Lưu ý Type of information các bạn để text, name tuỳ các bạn đặt và key chính là key mình đã define trong file userparameter.conf.

Chúng ta có thể test trước kết quả bằng cách bấm vào test và bấm vào Get value, kết quả chúng ta có 1 dữ liệu đầu ra là dạng json giống kết quả khi chúng ta chạy file /usr/local/bin/interface_status.py. Hãy bấm Add để tiến hành thêm item này.

Chúng ta sẽ có 1 Item với như vậy.

Hãy vào Latest data kiểm tra dữ liệu đã đổ vào chưa bằng cách bấm vào history của item vừa tạo.

Chúng ta có kết quả như dưới.

Tiếp theo để lấy các thông tin cụ thể trong đống dữ liệu dưới bạn hãy tạo 1 item mới, lưu ý là mỗi thông tin lấy bạn sẽ tạo 1 item nhé. Ở phần này Name và Key các bạn tự define, do dữ liệu đầu ra của mình chính là trạng thái của các cổng Up/Down, nó là dạng chữ nên mình để Type of information là Text, hãy bấm vào Select ở tuỳ chọn Master item.

Bạn chọn item Parent Interface Status, đây chính là item chứa đống dữ liệu json của bạn.

Bạn có kết quả như dưới.

Bây giờ chuyển qua thẻ Preprocessing, tại Preprocessing steps chúng ta chọn JSONPath (lý do data của chúng ta ở dạng json), tại Parameters chúng ta gõ vào $[*].[‘Ethernet1/50’].

Trong trường hợp này, JSON là một mảng (array) các đối tượng (object), mỗi đối tượng đại diện cho một cổng Ethernet và trạng thái của nó. Cụ thể, đối tượng đầu tiên {“Ethernet1/50”: “Up”} biểu thị cho cổng Ethernet1/50 và trạng thái của nó là “Up”.

Paser $[*].[‘Ethernet1/50’] là một biểu thức JMESPath (một ngôn ngữ truy vấn dữ liệu JSON) để truy xuất và lấy giá trị của thuộc tính “Ethernet1/50” trong mỗi đối tượng của mảng.

Vì vậy, khi sử dụng biểu thức này, bạn sẽ nhận được một mảng mới chứa các giá trị của thuộc tính “Ethernet1/50” trong mỗi đối tượng ban đầu. Trong trường hợp này, kết quả sẽ là một mảng [“Up”] vì chỉ có một đối tượng trong mảng ban đầu chứa thuộc tính “Ethernet1/50”.

Mình sẽ giải thích ý nghĩa của từng ký tự trong biểu thức JMESPath $[*].[‘Ethernet1/50’]:

  • $: Đây là ký tự đầu tiên trong biểu thức JMESPath, đại diện cho “root” (gốc) của đối tượng JSON. Nó cho biết rằng biểu thức truy vấn sẽ bắt đầu từ đầu của đối tượng JSON.
  • [*]: Đây là toán tử lặp lại (wildcard), cho biết rằng biểu thức JMESPath sẽ lặp lại qua tất cả các phần tử của mảng đối tượng JSON. Toán tử này sử dụng dấu ‘*’ để chỉ định rằng tất cả các phần tử của mảng đối tượng sẽ được truy xuất.
  • .: Đây là toán tử chấm (dot), cho biết rằng chúng ta sẽ tiếp tục truy cập vào các thuộc tính của đối tượng JSON.
  • ['Ethernet1/50']: Đây là toán tử truy cập thuộc tính, cho biết rằng chúng ta muốn truy cập vào thuộc tính “Ethernet1/50” của mỗi đối tượng JSON.

Vì vậy, biểu thức JMESPath $[*].[‘Ethernet1/50’] có nghĩa là “truy xuất tất cả các giá trị của thuộc tính ‘Ethernet1/50’ từ mọi đối tượng trong mảng JSON”.

Hãy bấm vào test để chúng ta kiểm chứng kết quả.

Hãy cho 1 đoạn dữ liệu dạng json vào tuỳ chọn Value.

Ví dụ như dưới.

Bạn hãy bấm Test và bạn sẽ có kết quả [“Up”] tại mục Result.

Vì kết quả là [“Up”] mà mình chỉ muốn lấy Up mà thôi, vậy mình sẽ dùng công cụ Trim để cắt “[ và ]” ra khỏi [“Up”] để kết quả cuối cùng phải là Up.

Chúng ta bấm vào Test all steps để kiểm chứng, hãy nhớ truyền dữ liệu vào và bấm Test. Bạn thấy kết quả khi chạy JSONPath là [“Up”] và khi chạy Trim là Up, như vậy kết quả cuối cùng là Up.

Sau khi thêm xong item trên chúng ta có 2 item như dưới với item Parent Interface Status là cha và Parent Interface Status: Ethernet1/50 Status là item con (tức là item phụ thuộc).

Hãy vào Latest data và bạn có kết quả, 2 item chúng ta tạo đã nhận được value.

Kết quả value của item phụ thuộc là giá trị Up hoặc Down tuỳ vào trạng thái cổng trên thiết bị switch.

/usr/local/bin/interface_status.py

#!/usr/bin/python3
import subprocess, json

get_name = subprocess.check_output("""snmpwalk -v3 -u demo -l authPriv -a MD5 -A 123abcxyz -x DES -X 123abcxyz 103.15.49.2 1.3.6.1.2.1.2.2.1.2""", shell=True).decode('utf-8').strip('\n').split('\n')
get_status = subprocess.check_output("""snmpwalk -v3 -u demo -l authPriv -a MD5 -A 123abcxyz -x DES -X 123abcxyz 103.15.49.2 1.3.6.1.2.1.2.2.1.8""", shell=True).decode('utf-8"').strip('\n').split('\n')

list_interface_status = []

for x in get_name:
    interface_name = x.split(':')[-1].strip().strip('"')
    oid_interface_name = x.split()[0].split('.')[10]
    for y in get_status:
        interface_status = y.split('INTEGER:')[-1]
        oid_interface_status = y.split(' = INTEGER: ')[0].split('.')[10]
        if int(interface_status) == int(2):
            status = 'Down'
        else:
            status = 'Up'
        if oid_interface_name == oid_interface_status:
            dict_interface_status = {
                interface_name: status
            }
            list_interface_status.append(dict_interface_status)

print(json.dumps(list_interface_status))

Kết quả khi ta chạy python3 /usr/local/bin/interface_status.py.

[{"mgmt0": "Down"}, {"Vlan1": "Down"}, {"Vlan2": "Up"}, {"Vlan4": "Up"}, {"Vlan5": "Up"}, {"Vlan6": "Up"}, {"Vlan7": "Up"}, {"Vlan8": "Up"}, {"Vlan9": "Up"}, {"Vlan20": "Up"}, {"Vlan21": "Up"}, {"Vlan31": "Up"}, {"Vlan32": "Up"}, {"Vlan33": "Up"}, {"Vlan34": "Up"}, {"Vlan35": "Up"}, {"Vlan36": "Up"}, {"Vlan37": "Up"}, {"Vlan38": "Up"}, {"Vlan39": "Up"}, {"Vlan47": "Up"}, {"Vlan99": "Up"}, {"Vlan100": "Up"}, {"Vlan101": "Up"}, {"Vlan102": "Up"}, {"Vlan103": "Up"}, {"Vlan150": "Up"}, {"port-channel1": "Up"}, {"port-channel2": "Up"}, {"port-channel22": "Down"}, {"port-channel24": "Down"}, {"port-channel26": "Down"}, {"port-channel28": "Down"}, {"port-channel30": "Down"}, {"port-channel32": "Down"}, {"port-channel34": "Down"}, {"port-channel36": "Down"}, {"port-channel45": "Down"}, {"port-channel46": "Up"}, {"port-channel51": "Up"}, {"port-channel52": "Up"}, {"port-channel99": "Down"}, {"port-channel100": "Up"}, {"Ethernet1/1": "Down"}, {"Ethernet1/2": "Down"}, {"Ethernet1/3": "Down"}, {"Ethernet1/4": "Down"}, {"Ethernet1/5": "Down"}, {"Ethernet1/6": "Down"}, {"Ethernet1/7": "Up"}, {"Ethernet1/8": "Down"}, {"Ethernet1/9": "Down"}, {"Ethernet1/10": "Down"}, {"Ethernet1/11": "Up"}, {"Ethernet1/12": "Down"}, {"Ethernet1/13": "Down"}, {"Ethernet1/14": "Down"}, {"Ethernet1/15": "Down"}, {"Ethernet1/16": "Down"}, {"Ethernet1/17": "Down"}, {"Ethernet1/18": "Down"}, {"Ethernet1/19": "Up"}, {"Ethernet1/20": "Down"}, {"Ethernet1/21": "Down"}, {"Ethernet1/22": "Down"}, {"Ethernet1/23": "Down"}, {"Ethernet1/24": "Down"}, {"Ethernet1/25": "Down"}, {"Ethernet1/26": "Down"}, {"Ethernet1/27": "Down"}, {"Ethernet1/28": "Down"}, {"Ethernet1/29": "Down"}, {"Ethernet1/30": "Up"}, {"Ethernet1/31": "Down"}, {"Ethernet1/32": "Down"}, {"Ethernet1/33": "Up"}, {"Ethernet1/34": "Down"}, {"Ethernet1/35": "Up"}, {"Ethernet1/36": "Down"}, {"Ethernet1/37": "Up"}, {"Ethernet1/38": "Down"}, {"Ethernet1/39": "Up"}, {"Ethernet1/40": "Up"}, {"Ethernet1/41": "Up"}, {"Ethernet1/42": "Down"}, {"Ethernet1/43": "Up"}, {"Ethernet1/44": "Up"}, {"Ethernet1/45": "Down"}, {"Ethernet1/46": "Up"}, {"Ethernet1/47": "Up"}, {"Ethernet1/48": "Up"}, {"Ethernet1/49": "Up"}, {"Ethernet1/50": "Up"}, {"Ethernet1/51": "Down"}, {"Ethernet1/52": "Up"}]

Ví dụ nội dung trong file /etc/zabbix/zabbix_agentd.d/userparameter.conf.

UserParameter=cisco.interface.status,interface_status.py

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories