Child pages
  • Валидация конфигурации или "Факты, только факты и ничего кроме фактов"
Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Введение

Для начала рекомендуется прочитать статью .........

О фактах

Валидацию можно описать как процесс сравнения некоторого актуального состояния реальности с эталоном. При этом, само актуальное состояние можно представить в виде фактов. Н-р, идёт дождь, скорость машины 90 км/ч. В случае конфигурации оборудования, будет так: маршут по умолчанию 127.0.0.1, NTP сервер 1.1.1.1 и т.д.... Для удобства валидации, хорошо бы извлекать факты из конфигурации. Этим занимается парсер фактов.

В задачу парсера входит проход конфигурации и заполнение фактов на её основе. Т.е. на вход парсер получает конфигурациюю оборудования, собранную дискавери, а на выходе некоторый набор фактов, который, после записи в систему будет доступен для использования при валидации конфигурации.

Конечно, отсутствие извлечённых фактов не мешает нам осуществлять в конфигурации какие-либо проверки конфигурации другими инструментами (н-р регулярные выражения, совпадения строк ...), но их наличие сильно упрощает жизнь при написании сложных проверок.

Список доступных для заполнения фактов можно найти в папке cm/facts/*.py. Каждый файл описывает отдельную сущность. В него можно зайти и посмотреть доступные для заполнения поля:

  • interface
  • subinterface
  • service
  • ntpserver
  • staticroute
  • sysloghost
  • system
  • user
  • vlan
  • vrf

Наш парсер

И так, как же нам написать свой парсер конфигурации и получить многие знания, имея доступ только к конфигурации оборудования? Сами по себе парсеры лежат в папке cm/parsers. Структура подпапок напоминает структуру профилей оборудования в sa/profiles. Парсеры в НОКе можно, условно, поделить на 2 типа: использующие библиотеку pyparsing и самописные (не использующие эту библиотеку). Попробуем показать оба подхода, на примере создания парсера для Huawei.

PyParsing

Представляет из себя анализатор текстов. Позволяет разбивать их на различные лексически единицы (читай слова) и дальше что-то с ними делать. Фактически, парсер, написанный с применением pyparsing и выглядит как описание структуру текста с тем, что с ними делать. Н-р на нём написан парсер для Cisco.IOS cm/parsers/Cisco/IOS/base.py. Для лучшего ознакомления с этим инструментом необходимо прочитать статьи:

Работа с pyparsing чем-то напоминает работу с регулярными выражениями, только здесь проще синтаксис и понятнее что мы делаем. В нашем случае основным понятием для парсинга будут токены (TOKENS). Токены могут состоять из различных элементов и объединяться с друг другом. Для удобства уже присутствуюет некоторый набор токенов, его можно найти в файле cm/parsers/tokens.py. В самом файле они приведены с примерами использования, поэтому рассмотрим некоторые:

 

  • SPACE = Suppress(Word(" ").leaveWhitespace()) - Описывает пробел/s (слово Word(" ").leaveWhitespace()), который/е необходимо пропустить (слово Suppress)
  • INDENT = Suppress(LineEnd() + SPACE) - Описывает конструкцию вида "\n\s+" т.е. перевод строки (LineEnd()) после которого идут пробелы (SPACE)
  • REST = SPACE + restOfLine - ключевое слово restOfLine обозначает до конца строки

С остальными конструкциями можно ознакомиться самостоятельно.

Для проверки своих токенов подойдёт ./noc shell или локальный интерпретатор python. Поступаем так:

from pyparsing import *
from noc.cm.parsers.tokens import INDENT, REST

config_cisco = """service timestamps debug datetime
service timestamps log datetime
service password-encryption
!
hostname C2960_2
!
no logging console
"""
HOSTNAME = LineStart() + Literal("hostname") + REST.copy()
HOSTNAME.searchString(config)
Out[60]: ([(['hostname', 'C2960_2'], {})], {})
config_huawei = """!Software Version V100R005C01SPC100
 sysname Huawe23_Stack
#
 vlan batch 2 to 91 95 to 590 592 to 596 600 to 4089
#
 stp instance 0 priority 16384
 stp enable
#
"""
HOSTNAME = INDENT + Literal("sysname") + REST.copy()
HOSTNAME.searchString(config)
Out[13]: 
([(['sysname', 'Huawe23_Stack'], {})], {})

в переменную config можно положить конфигурацию оборудования и экспериментировать с парсингом.

После того как токены извлечены, можно начинать писать их обработку. Для этого применяются небольшие функции-методы, которым на вход поступает токен, а они устанавливают факт. Выглядят они так:

def on_vlan_range(self, tokens):
    for v in ranges_to_list(tokens[0].strip()):
        self.get_vlan_fact(v)

def on_vlan_name(self, tokens):
    self.get_current_vlan().name = tokens[0]

def on_http_server(self, tokens):
    self.get_service_fact("http").enabled = tokens[0] != "undo"

Они вызываются путём использования конструкции .setParseAction(self.on_interface_ndp). Она позволяет, при совпадении с токенов вызвать обработчик для одного из элементов или всего токена и передать его на обработку.

 

После того, как мы научились извклекать необходимые нам факты

 

Handmade

Что-то пошло не так....

Теперь, когда парсер написан, необходимо подключить его к профилю и проверить. Подключение делается путём прописывания конструкции default_parser = "noc.cm.parsers.Huawei.VRP.base.BaseVRPParser" в файл __init__.py соотв. профиля. Для тестирования парсера удобно использоваться shell:

Необходимо помнить, что при дискавери парсинг фактов происходит только при изменении в конфигурации. Т.е., простой запуск дискавери, не будет приводить к отработке парсера.

import logging
from noc.lib.debug import error_report
from noc.cm.engine import Engine
from noc.sa.models.managedobject import ManagedObject

# Получаем необходимый MO, конфигурацию которого будем парсить
mo = ManagedObject.objects.get(name=MO_NAME)
# Выставляем уровень логгирования на отладку
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
 
engine = Engine(mo)
# Запускаем парсинг конфига
try:
	engine.check()
except:
    print error_report()

На выходе получаем огромную простыню вывода. Если в парсере есть какие-то ошибки - будет трейс. Смотрим и разбираемся что не так

  • No labels