І знову автоматизація: Python «доповзла» до маршрутизаторів

image

Швидкість розвитку технологій в наші дні вражає. Стрибок науково-технічного прогресу в останні роки можна порівняти хіба що з темпами розвитку космічної галузі в період з кінця 50-х по середину 70-х років ХХ століття. Як тоді присутність людини в космосі стало реальністю, так само і зараз повсюдна заміна людей машинами вже не здається чимось захмарним.

Автоматизація процесів стала повноцінним «трендом» нашого часу і продовжує розширювати свій вплив практично у всіх сферах діяльності: починаючи з сільського господарства і закінчуючи «розумними будинками» або штучним інтелектом.

Дана тенденція диктує свої правила гри і в сфері бізнесу. Гравці ринку, недостатньо інвестують в оптимізацію своїх бізнес — та виробничих процесів, їх здешевлення і прискорення шляхом автоматизації, зовсім скоро опиняться за бортом».

Автоматизація виробництва – це, якщо хочете, вже гігієна. І мова тут йде про виробництво автомобілів (із заміною ручної збірки конвеєром), так і про виробництві програмного забезпечення (з заміною ручного тестування автотестами) або наданні послуг зв'язку (з заміною ручної праці телефоністок спочатку на комутаційне обладнання, а потім і зовсім на нові технології зв'язку).

Розуміючи важливість автоматизації в сучасних реаліях, ми в компанії Huawei вважаємо важливим і корисним ділитися нашим досвідом автоматизації роботи мережевого устаткування Huawei c користувачами нашої продукції і представляємо вашій увазі цикл постів, присвячених автоматизації.

У «першої серії» піде мова про засоби управління подіями, реалізованих в обладнанні Huawei.

Управління подіями
Будь мережевий протокол містить в собі опис реакції на певні події. Наприклад, при падінні інтерфейсу, включеного в процес OSPF або RIP, маршрутизатор, який знайшов це подія, розсилає повідомлення своїм сусідам. Але безліч реакцій на події, реалізоване у будь-якому стандартному протоколі, не вичерпує всього різноманіття завдань, з якими може зіткнутися фахівець, що обслуговує систему. Розглянемо приклад:
image
В даному випадку, як ми бачимо, по кожному зовнішньому каналу передаються як дані, так і голос: налаштований QoS, виділяє по 50% пропускної спроможності кожного каналу для голосового трафіку. Але при падінні одного з каналів необхідно змінити налаштування залишився таким чином, щоб пріоритетна чергу для голосового трафіку займала не 50%, а 70%.

Це завдання, безумовно, можна вирішити з використанням NMS — або SDN-контролера (тобто зовнішньої керуючої системи). Також, ймовірно, можна її вирішити і стандартними засобами на маршрутизаторі, але дане рішення дуже неочевидно.

Особливо в більш складною (як і наше життя :) ) ситуації, де швидкості каналів різні і приймаються вони на різні маршрутизатори:

image
Ось тут-то і приходить «зоряний годину» системи управління подіями, яка була впроваджена нашою компанією в мережеву OS Huawei.

Система управління подіями OPS (Open-Programming System) дозволяє автоматично виконувати певний набір дій (змінювати конфігурацію, зберігати файл або що-небудь ще) при виникненні певних подій.

Перейдемо до деталей.

Обладнання, що підтримує OPS
Система OPS в даний момент підтримується на комутаторах серії CE і на маршрутизаторах серій NE40 і AR. У кожної з цих моделей має свої особливості підтримки OPS, яких ми обов'язково розглянемо.

Програмування
Правила реакції на події в загальному випадку можна створювати з використанням CLI (командного рядка) або ж писати на Python (мовою програмування). Для опису самих правил можна також використовувати як CLI, так і Python. При цьому на комутаторах CE можна використовувати обидва інструменту, на маршрутизаторах AR – тільки Python, а на маршрутизаторах NE40 – лише командний рядок.

Давайте поглянемо на приклад опису події і реакції на нього за допомогою CLI.

Приклад #1:

[~CE]ops
[~CE-ops]assistant test1
[*CE-ops-assistant-test1]condition syslog pattern “.*Loopback[3-9].*own"
[*CE-ops-assistant-test1]execute 1.1 command sys
[*CE-ops-assistant-test1]execute 1.2 command int gi0/0/0
[*CE-ops-assistant-test1]execute 1.3 command undo shutdown
[*CE-ops-assistant-test1]execute 1.4 command commit
[*CE-ops-assistant-test1]commit
//Розшифруємо: якщо будь-який з інтерфейсів Loopback3, Loopback 41 і т. д. перейде в стан down, то інтерфейс Gigabit Ethernet 0/0/0 вийде зі стану administratively down.

В іншому прикладі опис події задано за допомогою CLI, а описана реакція на Python (у файлі backupconfig.py).

Приклад #2:

[~CE-ops] assistant Name /* create assistant */
[*CE-ops-assistant-Name] condition event feature configuration name cfg_file_change
[*SwitchA-ops-assistant-backup_config] execute 1 python backupconfig.py
[*SwitchA-ops-assistant-backup_config] commit
//Розшифруємо: при зміні файлу конфігурації запускається скрипт backupconfig.

Типи подій
З допомогою CLI можна налаштувати реакцію на такі типи подій:

  • запис в syslog;
  • запис в trapbuffer;
  • посилку або прийом SNMP;
  • виникнення аварії (alarm);
  • значення таймера.
Завдяки Python можна додатково відстежити:

  • уведення команди;
  • зміна маршруту;
  • зміна стану інтерфейсу;
  • результат роботи NQA (SLA).
Реакція на події
Найбільш часто використовуваним є зміна конфігурації пристрою. У найпростішому випадку за допомогою CLI задається послідовність команд (як показано в прикладі #1), другий параметр визначає послідовність виконання (в алфавітно-цифровому порядку).

У першому прикладі послідовно вводяться команди:

  1. Вхід в режим конфігурування (system-view);
  2. Вхід у подрежь конфігурування інтерфейсу Gigabit 0/0/0;
  3. Підняття інтерфейсу;
  4. Збереження змін.
OPS дозволяє вказати до 10 послідовних команд. Якщо ж необхідно виконати більше 10 команд, можна скористатися bat-файл і запустити його за допомогою команди execute 1 batch file-myfile.bat

Очевидно, з використанням Python можна застосовувати більш складні конструкції, ніж лінійне виконання послідовних команд конфігурування.

Крім простого виконання команд, OPS дозволяє:

  • зберігати і аналізувати збережені змінні;
  • висилати повідомлення на syslog-сервер;
  • повідомляти користувача, приймати від нього і аналізувати введення з терміналу;
  • виконувати вхід на віддалені пристрої з протоколів telnet, ssh та ін. і виконувати які-небудь дії.
Трохи магії на «Пітоні» :)
Розглянемо простий приклад оболонки (shell).

  1. Напишемо на Python найпростішу оболонку, яка буде зчитувати введення користувача і виконувати команди Python. На цьому прикладі розглянемо функції вводу/виводу на термінал, виконання команд і аналіз результату виконання.

    import os,sys
    def run©: 
    b=c.split()
    if b[0]== «ls»:
    if b.__len__() == 1:
    b.append(«/»);
    res = os.listdir(b[1])
    print
    print(res)
    else:
    try:
    exec©
    return 1
    except:
    print(«Something wrong»)
    return 0
    
    def get_command(ops,VTY):
    a, b = ops.terminal.write(«>>>«,vty = VTY)
    a, b = ops.terminal.read(maxLen = 200,timeout = 60,vty=VTY)
    if a==None:
    a='q';
    return a
    
    #Ставимо пастку на введення команди sh
    def ops_condition (ops):
    value, err_str = ops.cli.subscribe(«cli1», «^sh$», enter=True, sync=True, sync_wait=500)
    return 0
    # Власне, сам shell
    def ops_execute (ops):
    key, value = ops.environment.get(«_cli_vty»)
    while 2<3:
    command=get_command(ops,key)
    if command == «q»:
    break;
    if command <> ":
    run(command)
    continue
    print
    print(«exit\n»)
    return 0

    В даному випадку ми бачимо чотири функції:

    • run(command) – виконує команду command, повернуте значення не аналізується;
    • get_command(OPS,VTY) – на вхід подається вбудований об'єкт OPS і номер терміналу, повертає введену команду;
    • «пастку» ops_condition(OPS);
    • виконання ops_execute(OPS) – у разі спрацювання «пастки».
    Функції ops_condition(OPS) і ops_execute(OPS) є обов'язковими.

    run(command)
    Функція виконує команду Python. Якщо введена команда ls, якої в Python немає, то вона замінюється на наявну в Python команду os.listdir(path).

    Якщо рath не вказаний, робиться підстановка path="/". Таким чином можна створювати різні alias, тобто абревіатури, які будуть замінюватися на розгорнуті висловлювання.

    get_command(OPS,VTY)
    Зчитує і повертає користувальницький введення. Якщо введення не було протягом 60 секунд, повертає закінчення «q» – quit.

    ops_condition(OPS)
    «Пастка». У нашому випадку ставимо тригер на введення команди sh:
    ops.cli.subscribe(«cli1», «^sh$», enter=True, sync=True, sync_wait=500)
    "cli1" ім'я «пастки», потрібно для оброблення комплексного події, що складається з кількох «пасток»;
    ^sh$ – regexp, що описує рядок, що складається тільки з двох символів, а саме:
    sh. Наприклад, під regexp ^sh потрапила б і команда shutdown, sh – traffic-shaping.

    ops_execute(OPS)
    Спочатку зчитує ім'я терміналу в змінну key, а потім в нескінченному циклі (з допомогою нехитрого while 2<3) зчитує введення користувача в змінну command і виконує його (run(command)) або припиняє виконання if command==«q».

  2. Власне, подивимося, що вийшло. Введення користувача буде позначений болдом, а відповідь від маршрутизатора – синій кольором.

    Скрипт повинен бути скопійований на flash маршрутизатора, а потім його необхідно скомпілювати:

    <AR2>ops install file <scriptname.py>
    Потім необхідно створити assistant:
    <AR2>system view
    Enter system view, return user view with Ctrl+Z.
    [AR2]ops
    [AR2-ops]script-assistant python <scriptname.py>

    Перевіряємо:

    <AR2>sh
    >>>
    Отримали запрошення вводу. Тут потрібно зауважити, що контекст виконання в Python зберігається тільки всередині exec(). Ми не використовували форму exec(code,global,local), тому присвоєння значення змінної та його друк задаємо в одному рядку, тобто в межах одного і того ж exec.

    >>>a=2+3; print(«\n\r»);print a
    5

    Звичайно, можна було скористатися наступною формою:

    >>>global a
    >>>globals()[«a»]=2+3
    >>>print a

    Результат був би той самий, і насправді це не має значення, оскільки в реальних програмах ми не будемо використовувати exec майже ніколи, а цей простенький shell написаний лише для вивчення можливостей Python на маршрутизаторах Huawei.
Робота з файлами
>>>a=dir(os);print a['EX_CANTCREAT', ...'O_APPEND', 'O_ASYNC', 'O_CREAT', ..., 'O_RDWR', ...]

Як бачите, тут присутні константи для створення файлів, і тепер можна спробувати створити файл.

Будемо працювати з каталогом sd1: або /mnt/sd1 – це одне і те ж.

>>>ls /mnt/sd1
['AR2220-V200R003C01SPC900.cc',..., 'V600R008C10SPC300_RM.mod', 'AR2220-V200R007C00SPC600.cc', 'shelldir', 'python', ...]– бачимо, що у висновку присутні файли з sd1:. Порівняємо:
<AR2> dir
Directory of sd1:/
Idx Attr Size(Byte) Date Time(LMT) FileName
0 -rw — 94,689,536 Apr 23 2014 17:38:30 AR2220-V200R003C01SPC900.cc

22 -rw — 1,113,612 Dec 16 2015 14:38:44 V600R008C10SPC300_RM.mod
23 -rw — 123,975,040 Mar 15 2016 13:18:56 AR2220-V200R007C00SPC600.cc
24 drw- — Apr 01 2016 10:16:28 shelldir
25 drw- — Apr 06 2016 14:45:26 python

Найпростіший спосіб створити файл:

>>>os.system('echo qqq > /mnt/sd1/s.s')
<AR2> dir s*
Directory of sd1:/
Idx Attr Size(Byte) Date Time(LMT) FileName
9 -rw — 4 Oct 09 2016 17:24:15 s.s
1,961,192 KB total available (1,402,760 KB free)<AR2>more s.sQqq

Власне, ось і наш файл. Тепер виникає питання: як читати з нього? В даному випадку ми скористаємося тими засобами, які надає модуль os.

>>>f=os.open('/mnt/sd1/s.s',os.O_CREAT|os.O_RDWR);print f
47
>>>str='222';os.write(47,str)
>>>str='\n\r111';os.write(47,str)
>>>os.close(47)
<AR2>more s.s
222
111

До речі, аналогічного результату можна добитися, використовуючи os.system:

>>>os.system('echo 222 > /mnt/sd1/d.d')
>>>os.system('echo 111 >> /mnt/sd1/d.d')
<AR2>more d.d
222
111

Тепер прочитаємо з файлу:

>>>f=os.open('/mnt/sd1/s.s',os.O_RDONLY);print f
49
>>>s=os.read(49,8);print s
222
111

Як бачите, працювати з файлами в оболонці OPS досить просто, при цьому можна писати досить складні обробники подій, використовуючи описаний функціонал.

Функціонал, який забезпечує OPS, дозволяє вирішувати ті ж завдання, які вирішує аналогічна система управління подіями EEM (Embedded Event Management) від Cisco Systems, за винятком відправлення e-mail-повідомлень.

Але, по-перше, це лише перша реалізація Python, і в наступних версіях очікується додатковий функціонал. По-друге, e-mail все-таки можна надіслати через open relay, використовуючи telnet на порт 25. Функції для інших обробників і виконання дій повністю ідентичні Cisco EEM.

Кінець першої серії
Ми спробували продемонструвати деякі можливості застосування CLI і Python для управління подіями на маршрутизаторах Huawei. Наскільки це виявилося корисним, судити вам. Будемо раді побачити ваші коментарі, запитання та відгуки.

Ми ж, зі свого боку, продовжимо ділитися нашими напрацюваннями в області автоматизації роботи комунікаційного обладнання.

А поки завершимо першу серію словами юного Сергія Сироїжкіна, героя фільму «Пригоди Електроніка»:

До чого дійшов прогрес: праця фізична зник,
Та й розумовий замінить механічний процес.


Музика, титри, to be continued…
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.