返回文章列表

Jinja2 YAML 自動化網路裝置組態

本文探討如何結合 Jinja2 範本引擎與 YAML 資料格式,實作網路裝置的自動化組態管理。透過 Jinja2 的靈活語法和 YAML 的易讀性,可以簡化組態流程,提高效率並降低錯誤率。文章以 Cisco 路由器組態為例,逐步展示如何使用 Jinja2 範本渲染 YAML 資料,生成組態指令,並使用 Netmiko

網路工程 自動化

網路自動化已成為現代網路管理的根本,而 Jinja2 和 YAML 正是實作自動化的利器。Jinja2 作為範本引擎,負責定義組態的框架,YAML 則提供結構化的資料,兩者結合,讓網路工程師得以擺脫繁瑣的手動組態。本文將深入淺出地介紹如何運用 Jinja2 和 YAML,搭配 Python 及 Netmiko,實作 Cisco 路由器的自動化組態,包含主機名設定、介面組態以及批次佈署。透過實際案例,讀者將理解如何建構 Jinja2 範本、撰寫 YAML 資料檔案,並使用 Python 指令碼將兩者整合,最終透過 Netmiko 將組態推播至網路裝置。此方法不僅提升組態效率,更能有效降低人為錯誤,確保網路穩定執行。

網路自動化組態管理:Jinja2 與 YAML 的實務應用

在現代網路工程領域中,自動化組態管理已成為提升效率和降低錯誤率的關鍵技術。其中,Jinja2 範本引擎與 YAML 語言的結合使用,為網路裝置的組態管理提供了強大的工具。本文將探討 Jinja2 和 YAML 的基本概念,以及如何利用這兩種技術實作網路裝置的自動化組態。

Jinja2 範本引擎簡介

Jinja2 是一種流行的 Python 範本引擎,其語法與 Python 相似,具有高效、靈活的特點。在網路自動化領域,Jinja2 被廣泛用於生成網路裝置的組態範本。透過使用 Jinja2,網路工程師可以將組態範本與具體的組態資料分離,從而實作對多台網路裝置的統一管理和組態。

Jinja2 範本範例

以下是一個簡單的 Jinja2 範本範例,用於組態網路裝置的主機名和介面 IP 地址:

hostname {{ name }}
!
interface GigabitEthernet 0/1
ip address {{ ip_address }} {{ subnet_mask }}
no shutdown
!
interface GigabitEthernet 0/2
ip address {{ ip_address }} {{ subnet_mask }}
no shutdown
!

在這個範本中,{{ name }}{{ ip_address }}{{ subnet_mask }} 是變數,它們的值將在渲染範本時被具體的組態資料取代。

內容解密:

  1. hostname {{ name }}:設定網路裝置的主機名,{{ name }} 將被 YAML 檔案中的對應值取代。
  2. interface GigabitEthernet 0/1interface GigabitEthernet 0/2:組態兩個不同的介面,分別設定 IP 地址和子網路遮罩,並啟用介面。
  3. 使用 Jinja2 的優勢在於,可以根據不同的 YAML 組態檔案,生成適用於不同網路裝置的組態範本。

YAML 語言簡介

YAML(YAML Ain’t Markup Language)是一種人類友好的資料序列化語言,被廣泛應用於各種程式語言和工具中,包括 Ansible 這種流行的網路自動化工具。YAML 的語法簡單、易於閱讀,且支援多種資料型別,如字串、布林值、整數、浮點數、列表和字典。

YAML 語法要點

  • 縮排:YAML 使用縮排表示層級關係,與 Python 類別似。
  • 註解:使用 # 符號進行註解。
  • 大小寫敏感:YAML 語言區分大小寫。
  • 檔案副檔名:YAML 檔案通常以 .yaml.yml 為副檔名。

YAML 範例

以下是一個簡單的 YAML 檔案範例,用於定義 Jinja2 範本中的變數值:

name: Router1
ip_address: 192.168.1.1
subnet_mask: 255.255.255.0

這個 YAML 檔案定義了 nameip_addresssubnet_mask 三個變數,分別對應於 Jinja2 範本中的 {{ name }}{{ ip_address }}{{ subnet_mask }}

內容解密:

  1. name: Router1:定義了主機名變數 name 的值為 Router1
  2. ip_address: 192.168.1.1subnet_mask: 255.255.255.0:定義了 IP 地址和子網路遮罩的值。
  3. 這些值將被用於替換 Jinja2 範本中的對應變數,從而生成最終的網路裝置組態。

結合 Jinja2 與 YAML 實作自動化組態

要實作網路裝置的自動化組態,需要結合 Jinja2 範本和 YAML 組態檔案。以下是一個 Python 指令碼範例,展示瞭如何使用 Jinja2 和 YAML 模組渲染組態範本:

from jinja2 import Environment, FileSystemLoader
from yaml import safe_load

# 建立 Jinja2 環境並載入範本檔案
env = Environment(loader=FileSystemLoader("."))
template = env.get_template("commands.txt")

# 載入 YAML 組態檔案
with open("info.yml", "r") as file:
    data = safe_load(file)

# 渲染範本並輸出結果
rendered_config = template.render(data)
print(rendered_config)

內容解密:

  1. env = Environment(loader=FileSystemLoader(".")):建立一個 Jinja2 環境,並指定從當前目錄載入範本檔案。
  2. template = env.get_template("commands.txt"):載入名為 commands.txt 的 Jinja2 範本檔案。
  3. data = safe_load(file):使用 safe_load 方法載入 YAML 組態檔案中的資料。
  4. rendered_config = template.render(data):將 YAML 資料渲染到 Jinja2 範本中,生成最終的組態文字。

Jinja 範本與 YAML 檔案結合的網路裝置組態自動化

在網路自動化的過程中,Jinja 範本引擎與 YAML 檔案的結合使用可以大幅簡化網路裝置的組態管理工作。本章節將探討如何利用 Jinja 範本和 YAML 資料檔案來自動化組態 Cisco 路由器等網路裝置。

基本原理

Jinja 是一個功能強大的範本引擎,能夠讓使用者定義範本並將變數或表示式嵌入其中。YAML 檔案則用於儲存結構化的資料。透過 Jinja 的渲染功能,可以將 YAML 中的資料填充到範本中,生成最終的組態命令或檔案。

範例 5.6:使用 Jinja 範本與 YAML 檔案渲染組態

首先,我們建立一個名為 commands.txt 的 Jinja 範本檔案,其中包含了一個變數 language,被雙大括號包圍:

We try to learn {{ language }}

接著,建立一個名為 info.yml 的 YAML 檔案,用於儲存 language 的值:

language: Python

在 Python 指令碼中,我們使用 Jinja2 和 PyYAML 函式庫來讀取範本和 YAML 資料,並渲染出最終的組態:

from jinja2 import Environment, FileSystemLoader
from yaml import safe_load

# 設定 Jinja 環境並載入範本
env = Environment(loader=FileSystemLoader("."))
template = env.get_template("commands.txt")

# 載入 YAML 資料
with open("info.yml") as r:
    data = safe_load(r)

# 渲染範本
print(template.render(data))

程式碼解析:

  1. 載入 Jinja 範本:使用 FileSystemLoader 載入當前目錄下的 commands.txt 範本檔案。
  2. 讀取 YAML 資料:使用 safe_load 函式讀取 info.yml 檔案中的資料。
  3. 渲染範本:呼叫 render 方法,將 YAML 中的資料填充到 Jinja 範本中,生成最終輸出。

輸出結果為:We try to learn Python

範例 5.7:使用 Jinja 組態 Cisco 路由器

在這個範例中,我們將使用 Jinja 範本來組態 Cisco 路由器的主機名、介面描述、IP 位址和子網路遮罩。

commands.txt(Jinja 範本):

hostname {{ name }}
interface GigabitEthernet0/1
description {{ description }}
ip address {{ ip_address }} {{ subnet_mask }}
no shutdown

info.yml(YAML 資料):

name: Router-1
description: Test_Interface
ip_address: 192.168.10.10
subnet_mask: 255.255.255.0

Python 指令碼:

from jinja2 import Environment, FileSystemLoader
from yaml import safe_load
from netmiko import Netmiko
import re

# 路由器連線資訊
ip = {"host": "10.10.10.1", "username": "admin", "password": "cisco", "device_type": "cisco_ios", "global_delay_factor": 0.1}

# 載入 Jinja 範本和 YAML 資料
env = Environment(loader=FileSystemLoader("."))
template = env.get_template("commands.txt")
with open("info.yml") as r:
    data = safe_load(r)

# 渲染範本並轉換為命令列表
command = template.render(data)
command = re.split("\n", command)

# 連線到路由器並執行組態命令
print(f"\n
---
Try to Login: {ip['host']} 
---
\n")
net_connect = Netmiko(**ip)
output = net_connect.send_config_set(command)
print(output)

程式碼解析:

  1. Jinja 範本渲染:將 info.yml 中的資料填充到 commands.txt 範本中,生成路由器的組態命令。
  2. 命令分割:使用正規表示式將渲染後的命令字串分割成列表,以便逐行執行。
  3. Netmiko 連線:使用 Netmiko 函式庫連線到 Cisco 路由器,並執行組態命令。

使用迴圈進行批次組態

當需要對多個介面進行相同的組態時,可以在 Jinja 範本中使用迴圈來簡化操作。

範例 Jinja 範本:

{% for interface in interfaces %}
interface {{ interface.name }}
description {{ interface.description }}
ip address {{ interface.ip_address }} {{ interface.subnet_mask }}
{% endfor %}

範例 YAML 資料:

interfaces:
  - name: GigabitEthernet0/1
    description: Test_Interface_1
    ip_address: 192.168.10.10
    subnet_mask: 255.255.255.0
  - name: GigabitEthernet0/2
    description: Test_Interface_2
    ip_address: 192.168.20.10
    subnet_mask: 255.255.255.0

程式碼解析:

  1. 迴圈語法:在 Jinja 範本中使用 {% for %}{% endfor %} 定義迴圈,遍歷 YAML 中的 interfaces 清單。
  2. 變數參照:在迴圈內部,使用 {{ interface.name }}{{ interface.description }} 等語法參照每個介面的屬性。

透過這種方式,可以輕鬆地對多個介面進行相同的組態,大大提高了網路自動化的效率和靈活性。

使用 Jinja 範本組態多個介面與裝置

在網路自動化的領域中,Jinja 範本的使用大大簡化了組態管理的複雜性。透過結合 Python、YAML 以及 Jinja,我們可以輕鬆地對多個網路裝置進行組態。

範例 5.8:使用 Jinja 組態多個介面

在這個範例中,我們展示瞭如何使用 Jinja 範本來組態路由器的主機名稱以及多個介面的設定,包括介面描述、IP 位址以及啟用介面。

commands.txt:

hostname {{hostname}}
{% for int in interfaces %}
interface {{ int["name"] }}
description {{ int["description"] }}
ip address {{ int["ip_address"] }} {{ int["subnet_mask"] }}
no shutdown
{% endfor %}

info.yml:

hostname: Router-1
interfaces:
- name: GigabitEthernet0/1
  description: Service_Interface
  ip_address: 172.16.10.10
  subnet_mask: 255.255.255.0
- name: GigabitEthernet0/2
  description: MGMT_Interface
  ip_address: 10.0.0.10
  subnet_mask: 255.255.255.0
- name: GigabitEthernet0/3
  description: Dowlink_Interface
  ip_address: 1.1.1.1
  subnet_mask: 255.255.255.0

程式碼執行結果:

當我們執行 Python 程式碼後,Jinja 範本會根據 info.yml 中的資料生成組態命令,並套用到 Router-1 上。

R1(config)#hostname Router-1
Router-1(config)#
Router-1(config)#interface GigabitEthernet0/1
Router-1(config-if)# description Service_Interface
Router-1(config-if)# ip address 172.16.10.10 255.255.255.0
Router-1(config-if)# no shutdown
...

內容解密:

  1. commands.txt Jinja範本:使用 {{hostname}} 將主機名稱動態插入組態中,並透過 for 迴圈遍歷 interfaces 清單,為每個介面生成相應的組態命令。
  2. info.yml 資料檔:定義了主機名稱和介面清單,每個介面包含名稱、描述、IP 位址和子網路遮罩等資訊。
  3. Python程式碼的作用:讀取 info.yml 中的資料,使用 Jinja 範本渲染出組態命令,並透過 Netmiko 將這些命令套用到目標裝置上。

範例 5.9:使用 Jinja 組態多個裝置

在這個範例中,我們展示瞭如何使用相同的 Jinja 範本和 Python 指令碼對多個裝置進行不同的組態。

commands.txt:

hostname {{hostname}}
interface {{int_name}}
description {{description}}
ip address {{ip_address}} {{subnet_mask}}
no shutdown

info.yml:

- hostname: R1
  int_name: GigabitEthernet0/3
  description: Test-1
  ip_address: 10.1.1.1
  subnet_mask: 255.255.255.0
- hostname: R2
  int_name: GigabitEthernet0/3
  description: Test-2
  ip_address: 10.1.1.2
  subnet_mask: 255.255.255.0
- hostname: R3
  int_name: GigabitEthernet0/3
  description: Test-3
  ip_address: 10.1.1.3
  subnet_mask: 255.255.255.0

Python 指令碼:

from jinja2 import Environment, FileSystemLoader
from yaml import safe_load
from netmiko import Netmiko

# 裝置 IP 清單
ip_list = ["10.10.10.1", "10.10.10.2", "10.10.10.3"]

# 設定 Jinja 環境並載入範本
env = Environment(loader=FileSystemLoader("."))
template = env.get_template("commands.txt")

# 載入 YAML 資料
with open("info.yml") as f:
    data = safe_load(f)

# 對每個裝置進行組態
for x, ip in zip(data, ip_list):
    device = {
        "host": ip,
        "username": "admin",
        "password": "cisco",
        "device_type": "cisco_ios"
    }
    command = template.render(x)
    command = command.split("\n")
    net_connect = Netmiko(**device)
    output = net_connect.send_config_set(command)
    print(output)

內容解密:

  1. 同時組態多個裝置:透過迴圈遍歷裝置 IP 清單和對應的組態資料,使用 Jinja 範本為每個裝置生成組態命令。
  2. 動態渲染範本:根據 info.yml 中的資料動態替換 Jinja 範本中的變數,生成最終的組態命令。
  3. 使用 Netmiko 連線裝置:將生成的組態命令套用到每個裝置上,實作自動化組態。