Aruba CX Switch Network Analytics Engine (NAE) 入門

Network Analytics Engine 是 Python環境 並且透過 REST API去做資料收集分析行動的功能。

因此,想要入門NAE, 建議就有「Python基礎」與「REST API」等相關知識,這部分可以看網路上很多文章與影片,就能準備基本的背景知識。

Getting Started with NAE

根據官方文件,上圖可以表示NAE所有部分。如果要造出屬於自己環境的腳本,就需要學習每個環節。這邊會簡單帶過,用一篇文章的幅度就能學會如何創造自己的腳本。

NAE改變過去Switch的管理方式,過去Switch透過Syslog或是SNMP,Switch都是被動的,會出現中央集中的log server或是snmp server去管理。

NAE透過仔細的API,腳本,行動,我們可以做到更靈活的狀態探知,並且使Switch變得主動。時間序資料庫也能保存紀錄並方便做成圖表。讓CX Switch可以不只是會因為重啟而消失的Current Data。

NAE可以使用外部REST API去觸發其他的工作流Webhook或是服務平臺的API服務,這能與現今發展趨勢吻合,也意味著你可以讓CX Switch在某些事件發生時,以telegram bot或是email等去通知。

本文,將會以「若介面1/1/1變成Down時,使用Telegram傳送訊息告知。」為目標。

瞭解NAE組成

https://arubanetworking.hpe.com/techdocs/AOS-CX/10.13/HTML/nae/Content/Chp_Scrpt/par-scr.htm

NAE是個由:Header、Import statements、Manifest、Parameter definitions、Agent class constructor組成。

如果有寫過Python,Header與Import statements就不用多提。NAE能import的python庫,詳細能用什麼可以點連結。

Manifest:說明此Script相關資訊以及適用版本型號

Parameter definitions: 可以讓使用者調整的參數,若未調整,在此定義初始值。使用者可以在NAE-Agent啟動指定Script時,帶入參數「名稱:值(base64)」。

Agent class constructor:監控(Moniter)、規則(Rule)、條件(Condition)、行動(Action)。

NAE-Lite是個更簡易的NAE部署,透過CLI,設定Agent class constructor四要件,就可以造出。不過本文目標所用的功能更高遠,就不提此功能。

Switch型號與NAE Script與Agent數限制

隨著型號越高,NAE能使用的數量上限也會增加,詳情可以參考上表。

NAE 各部分說明

https://arubanetworking.hpe.com/techdocs/AOS-CX/10.13/HTML/nae/Content/Chp_Scrpt/scr-exa.htm

「若介面1/1/1變成Down時,使用Telegram傳送訊息告知。」這目標。

NAE Agent四要件就是:
監控(Moniter):透過REST API去取得特定介面1/1/1的link_status。
規則(Rule):方便閱讀的條件說明「interface 1/1/1 down」。
條件(Condition):一個判斷式,這邊為link_status是否等於down。
行動(Action):傳入參數event,並執行類別函式,函式功能則是用Requests去使用Telegram Bot Notify。

Manifest隨意打打。ParameterDefinitions甚至可以不用。Import statements只需要導入requests。

監控(Moniter)

Monitor為一個類別,裡面需要指令REST API URL,後面則看需求。

# 類別
Monitor(url, <params>)

# 部分程式碼
url = "/rest/v10.13/system/interfaces/1%2F1%2F1?attributes=link_state"
self.specific_interface_status = Monitor(url, 'specific_interface status')

如果url內有特殊字符,後面參數就能替換特殊字符。要把特殊字符換上有很多方法,這邊以直接指定1/1/1,不做替換。

如何取得特定資訊的REST API URL?

透過Web UI連入CX Switch,右上方齒輪icon,點開後可以看到API,點擊進入就能進入CX Switch REST API的測試頁面。

測試頁面功能請務必先執行Login功能!!

這樣測試頁面才會帶有Token,其他REST API功能才能正常使用!

調用目的API之前,記得先使用Login去登入。

然後找到目標API,interface/1/1/1,執行,就能順利得到回傳(code:200)。

到此,已經找出取的特定介面1/1/1的Requests URL。

https://172.26.1.104/rest/v10.13/system/interfaces/1%2F1%2F1?attributes=link_state

去掉IP等前綴,只保留相對路徑 =>
/rest/v10.13/system/interfaces/1%2F1%2F1?attributes=link_state

規則(Rule)

說明此規則與條件,如果事件被觸發,可以在NAE上Alert看到Rule的說明。

self.r1 = Rule('Status - up -> down')

條件(Condition)

依附在Rule下,Condition為一個判斷式,第一個參數為True就會出發。這邊為link_status是否等於down。判斷式的參數可以為Moniter物件。

self.specific_interface_status = Monitor(url, 'specific_interface status')

#
self.r1.condition('{} == "down"',  [self.specific_interface_status])

行動(Action)

當Rule的Condition被滿足(True),就會觸發一個行動,觸發時會帶入Event,因此記得函式要保留此參數。

self.r1.action(self.action_interface_status_anomaly)

# called function
def action_interface_status_anomaly(self, event):
    self.telegram_notify("interface 1/1/1 down")
    self.set_alert_level(AlertLevel.CRITICAL)
    self.logger.info(f"================ {self.params['specific_interface']} down ================")

telegram_notify 參考

telegram_notify要能順利通知,要有bot_token與char_id,bot_token可以參考之前將HomeAssistant的LineNotify改為Telegram Bot – JN的電腦網路日常去取得。

    def telegram_notify(self, message):
        import requests
        url = f'https://api.telegram.org/bot{self.telegram_api_key}/sendMessage'
        payload = {
            'chat_id': self.telegram_chat_id,
            'text': message
        }     
        requests.post(url, data=payload, timeout=10)

完整NAE Script

筆者在過程中參考很多ASE的範本,也消化官方文件,最後寫成一份可用的。

# jnnetlab.com
# JN

Manifest = {
    'Name': 'interface_monitor_and_notify_telegram',
    'Description': 'Monitor specific interface. if it shutdowns, notify manager by telegram',
    'Version': '1.0',
    'Author': 'JN'
}

ParameterDefinitions = {
    'specific_interface': {
        'Name': 'specific_interface',
        'Description': 'specific_interface',
        'Type': 'string',
        'Required': True,
        'Default': '1/1/1'
    },
    'telegram_api_key': {
        'Name': 'telegram_api_key',
        'Description': 'telegram_api_key',
        'Type': 'string',
        'Required': True,
        'Default': ''
    },    
    'telegram_chat_id': {
        'Name': 'telegram_chat_id',
        'Description': 'telegram_chat_id',
        'Type': 'string',
        'Required': True,
        'Default': ''
    },      
    }

class Agent(NAE):
    def __init__(self):
        url = "/rest/v10.13/system/interfaces/1%2F1%2F1?attributes=link_state"
        self.specific_interface_status = Monitor(url, 'specific_interface status')
        self.r1 = Rule('Status - up -> down')
        self.r1.condition('{} == "down"',  [self.specific_interface_status])
        self.r1.action(self.action_interface_status_anomaly)
        self.r1.clear_condition('{} == "up"', [self.specific_interface_status])
        self.r1.clear_action(self.return_to_normal)
        self.telegram_api_key = self.params['telegram_api_key']
        self.telegram_chat_id = self.params['telegram_chat_id']

    def action_interface_status_anomaly(self, event):
        self.telegram_notify("interface 1/1/1 down")
        self.set_alert_level(AlertLevel.CRITICAL)
        self.logger.info(f"================ {self.params['specific_interface']} down ================")

    def return_to_normal(self, event):
        self.remove_alert_level()
        self.logger.info(f"================ {self.params['specific_interface']} up ================")

    def telegram_notify(self, message):
        import requests
        url = f'https://api.telegram.org/bot{self.telegram_api_key}/sendMessage'
        payload = {
            'chat_id': self.telegram_chat_id,
            'text': message
        }     
        requests.post(url, data=payload, timeout=10)

成果

故意將1/1/1的設備重啟,觸發interface 1/1/1 down。

Telegram收到通知

Plaintext轉換base64

Base64 编码/解码 – 锤子在线工具

線上有很多工具。要用CLI導入python,就需要先把文本以base64編碼,這時就能使用以上工具網站。如果要帶入參數,就需要把參數值也轉成base64。

如果有個參數為interface,值想要帶入1/1/1,這時需要先把1/1/1以base64編碼,參數與值中間使用「:」,值以base64編碼輸入。

interface:1/1/1
=>
interface:MS8xLzE=

CLI部署NAE Script與NAE Agent

# python的部分要用base64編碼
nae-script jn1234 false IyBqbm5ldGxhYi5jb20KIyBKTgoKTWFuaWZlc3QgPSB7CiAgICAnTmFtZSc6ICdpbnRlcmZhY2VfbW9uaXRvcl9hbmRfbm90aWZ5X3RlbGVncmFtJywKICAgICdEZXNjcmlwdGlvbic6ICdNb25pdG9yIHNwZWNpZmljIGludGVyZmFjZS4gaWYgaXQgc2h1dGRvd25zLCBub3RpZnkgbWFuYWdlciBieSB0ZWxlZ3JhbScsCiAgICAnVmVyc2lvbic6ICcyLjAnLAogICAgJ0F1dGhvcic6ICdKTicKfQoKUGFyYW1ldGVyRGVmaW5pdGlvbnMgPSB7CiAgICAnc3BlY2lmaWNfaW50ZXJmYWNlJzogewogICAgICAgICdOYW1lJzogJ3NwZWNpZmljX2ludGVyZmFjZScsCiAgICAgICAgJ0Rlc2NyaXB0aW9uJzogJ3NwZWNpZmljX2ludGVyZmFjZScsCiAgICAgICAgJ1R5cGUnOiAnc3RyaW5nJywKICAgICAgICAnUmVxdWlyZWQnOiBUcnVlLAogICAgICAgICdEZWZhdWx0JzogJzEvMS8xJwogICAgfSwKICAgICd0ZWxlZ3JhbV9hcGlfa2V5JzogewogICAgICAgICdOYW1lJzogJ3RlbGVncmFtX2FwaV9rZXknLAogICAgICAgICdEZXNjcmlwdGlvbic6ICd0ZWxlZ3JhbV9hcGlfa2V5JywKICAgICAgICAnVHlwZSc6ICdzdHJpbmcnLAogICAgICAgICdSZXF1aXJlZCc6IFRydWUsCiAgICAgICAgJ0RlZmF1bHQnOiAnJwogICAgfSwgICAgCiAgICAndGVsZWdyYW1fY2hhdF9pZCc6IHsKICAgICAgICAnTmFtZSc6ICd0ZWxlZ3JhbV9jaGF0X2lkJywKICAgICAgICAnRGVzY3JpcHRpb24nOiAndGVsZWdyYW1fY2hhdF9pZCcsCiAgICAgICAgJ1R5cGUnOiAnc3RyaW5nJywKICAgICAgICAnUmVxdWlyZWQnOiBUcnVlLAogICAgICAgICdEZWZhdWx0JzogJycKICAgIH0sICAgICAgCiAgICB9CgpjbGFzcyBBZ2VudChOQUUpOgogICAgZGVmIF9faW5pdF9fKHNlbGYpOgogICAgICAgIHVybCA9ICIvcmVzdC92MTAuMTMvc3lzdGVtL2ludGVyZmFjZXMvMSUyRjElMkYxP2F0dHJpYnV0ZXM9bGlua19zdGF0ZSIKICAgICAgICBzZWxmLnNwZWNpZmljX2ludGVyZmFjZV9zdGF0dXMgPSBNb25pdG9yKHVybCwgJ3NwZWNpZmljX2ludGVyZmFjZSBzdGF0dXMnKQogICAgICAgIHNlbGYucjEgPSBSdWxlKCdTdGF0dXMgLSB1cCAtPiBkb3duJykKICAgICAgICBzZWxmLnIxLmNvbmRpdGlvbigne30gPT0gImRvd24iJywgIFtzZWxmLnNwZWNpZmljX2ludGVyZmFjZV9zdGF0dXNdKQogICAgICAgIHNlbGYucjEuYWN0aW9uKHNlbGYuYWN0aW9uX2ludGVyZmFjZV9zdGF0dXNfYW5vbWFseSkKICAgICAgICBzZWxmLnIxLmNsZWFyX2NvbmRpdGlvbigne30gPT0gInVwIicsIFtzZWxmLnNwZWNpZmljX2ludGVyZmFjZV9zdGF0dXNdKQogICAgICAgIHNlbGYucjEuY2xlYXJfYWN0aW9uKHNlbGYucmV0dXJuX3RvX25vcm1hbCkKICAgICAgICBzZWxmLnRlbGVncmFtX2FwaV9rZXkgPSBzZWxmLnBhcmFtc1sndGVsZWdyYW1fYXBpX2tleSddCiAgICAgICAgc2VsZi50ZWxlZ3JhbV9jaGF0X2lkID0gc2VsZi5wYXJhbXNbJ3RlbGVncmFtX2NoYXRfaWQnXQoKICAgIGRlZiBhY3Rpb25faW50ZXJmYWNlX3N0YXR1c19hbm9tYWx5KHNlbGYsIGV2ZW50KToKICAgICAgICBzZWxmLnRlbGVncmFtX25vdGlmeSgiaW50ZXJmYWNlIDEvMS8xIGRvd24iKQogICAgICAgIHNlbGYuc2V0X2FsZXJ0X2xldmVsKEFsZXJ0TGV2ZWwuQ1JJVElDQUwpCiAgICAgICAgc2VsZi5sb2dnZXIuaW5mbyhmIj09PT09PT09PT09PT09PT0ge3NlbGYucGFyYW1zWydzcGVjaWZpY19pbnRlcmZhY2UnXX0gZG93biA9PT09PT09PT09PT09PT09IikKCiAgICBkZWYgcmV0dXJuX3RvX25vcm1hbChzZWxmLCBldmVudCk6CiAgICAgICAgc2VsZi5yZW1vdmVfYWxlcnRfbGV2ZWwoKQogICAgICAgIHNlbGYubG9nZ2VyLmluZm8oZiI9PT09PT09PT09PT09PT09IHtzZWxmLnBhcmFtc1snc3BlY2lmaWNfaW50ZXJmYWNlJ119IHVwID09PT09PT09PT09PT09PT0iKQoKICAgIGRlZiB0ZWxlZ3JhbV9ub3RpZnkoc2VsZiwgbWVzc2FnZSk6CiAgICAgICAgaW1wb3J0IHJlcXVlc3RzCiAgICAgICAgdXJsID0gZidodHRwczovL2FwaS50ZWxlZ3JhbS5vcmcvYm90e3NlbGYudGVsZWdyYW1fYXBpX2tleX0vc2VuZE1lc3NhZ2UnCiAgICAgICAgcGF5bG9hZCA9IHsKICAgICAgICAgICAgJ2NoYXRfaWQnOiBzZWxmLnRlbGVncmFtX2NoYXRfaWQsCiAgICAgICAgICAgICd0ZXh0JzogbWVzc2FnZQogICAgICAgIH0gICAgIAogICAgICAgIHJlcXVlc3RzLnBvc3QodXJsLCBkYXRhPXBheWxvYWQsIHRpbWVvdXQ9MTAp

#屬性值對,值的部分要用base64編碼
nae-agent jn1234 jn1234 false specific_interface:MS8xLzE= telegram_api_key:<your telegram_api_key encoded base64> telegram_chat_id:<your telegram_chat_id encoded base64>

1 則留言

留言功能已關閉。