Как стать автором
Обновить

Yast Another Config Manipulation или зачем изобретать велосипед?

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров686

Привет, Habr! Меня зовут Андрей, системный администратор в электрических сетях, со всеми вытекающими — сети, сервера, пользователи, программы. Как и у всех — какие то скрипты на python для сбора инфы с активки, ежедневного бэкапа конфигов, задач «а добавь вот этот IP в ACL на все устройства»

Везде использую свой модуль для работы с файлами конфигурации. Вы скажете OmegaConf Dynaconf, да и PYAML никто не отменял. Не торопитесь. Я попросил AI сравнить и воодушевился — а вдруг мой велосипед будет кому то полезен?

В начале было слово

Знакомство с python началось с книги Натальи Самойленко Python для сетевых инженеров
эксперименты ставил на своей сети, очень скоро осознал что для десятков устройств надо каждый раз готовить словарь device для ConnectHandler(**device), начал создавать такой в YAML файле. Формат этот мне больше всего понравился, принял для себя как «внутренний стандарт»

Это вылилось в создание своего модуля для работы с активкой, в котором в самом начале был класс StartOptions:

class StartOptions:
    
    def __init__(self, fi):
        from os import  path
        import psutil
        if not path.dirname(fi):
            p = psutil.Process().exe()
            path_to_ini = path.abspath(path.join(path.dirname(p), fi))
        else:
            path_to_ini = fi
        with open(path_to_ini, encoding="utf8") as f:
            d = yaml.safe_load(f)
        for key in d.keys():
            setattr(self, key, d[key])

myini = StartOptions('cb.yml')   

Создаем объект и устанавливаем ему атрибуты из keys() values() нашего конфига.
Погуглить имеющиеся решения на PYPi ума в тот момент и не хватило и хотелось что то свое написать.

пример конфига cb.yml:

language: ru
localpath: /opt/mypython/
main_backup_server:
  ftp_root: /var/ftp/CISCO/
  local_root: /var/ftp/CISCO/
  name: loganalyzer
  password: gAAAAABn7NmePUXNP7Yxni9dKi2H_ZqeQmAgv3AmbrNADgY23XrBVKB_rgmohFK321I9fbB_2bCAz5ShTJN3QSMGlwz5jVUNnA==^M
  user: gAAAAABn7Nme9PyPeK5Tm406au9B5NaN8FtnP33MAYo3DYkOTRnJKw0lBOROaw2iuKhSgDudHWePvWQ74WJi7iELvFglcvcE4g==^M
password: gAAAAABn7Nme6Kb4cI-sqsyApPFm2JsqLtp-2Hds7Jov8MY50XBx3s1VKOIXgA3FKjIa_FjpqkbdDsG6bWwzobwhw9SOrSwHOA==^M
phone_mac:
- 805e
- 001a
second_backup_server:
  ftp_root: /
  name: NOES-RPBSRV
  password: gAAAAABn7NmeOj75h2NeM8zzuySko3lVgEzEzTHkETALzcMv6s32XusxdRe9xseDFtJh0GPJpuuFEyeMmNq9h5vECRNgJicnsQ==^M
  user: gAAAAABn7NmeWRGa7UCv29ApgekzhYZdwXoN_PS_VJPjekvA72zzeQrJDv8GjsXKGHVT2_tfqJZHg0TgdoDaPhIvRSp7sJD-9w==^M
templpath: /opt/mypython/TEMPLATES/^M
user: gAAAAABn7NmekcfGhIjrwJRXL6v0QRm3SAz4dz-GSm16gu7dpBIyw5omo-A1d3-LjaNwPwTN6Vg-1jzW5_0aPeFbwe0p6TZtsQ=

Это реальный конфиг для скрипта бэкапа конфигураций всей активки. И пусть вас не удивляет не только main но и second backup server. Это цена опыта :-)

Зашифрованные строки появились уже потом. Используя свой модуль написал скрипт который по fh some_ip или fh some_host_name показывает в какой порт какого коммутатора (и путь от меня до него по сети) включен хост и, если это пользовательский АРМ в домене, еще и имя пользователя этого компьютера и имя хоста. Он полезен не только мне, но в конфиге в открытом виде мои учетки на tacacs и в AD,

Можно, конечно, создать ограниченные учетки для поиска (для AD у нас такая есть), но у меня лично один конфиг и для «покажи мне» и для «добавь на 100 500 устройств новый ACL

Поэтому прикрутил cryptography.fernet с созданием, обновлением «секрета» по ключу запуска с сохранением... в тело самой программы. Не понравилось. Стал хранить в отдельном файле. Пару раз менял принцип поиска, где лежит этот файл с секретом.

А потом попросил AI сравнить мой модуль с другими, он показал на какие‑то плюсы и началось — а хочешь добавим парсер/декодер, а хочешь добавим подсказки при наборе вида

 ac.main_backup_server
            language             password             templpath
            localpath            phone_mac            user
            main_backup_server   second_backup_server

а хочешь еще и поддержку JSON? согласился, сам подумывал. Не устоял еще и от .env от TOML отказался, но добавить не проблема.
И вот что поучилось:

Python module astarconf

Безопасный, подключаемый загрузчик конфигураций для YAML, JSON, .env и Python словарей - с шифрованием на уровне полей, поддержкой CLI и гибридным доступом.
Особенности

🔐 Шифрование/дешифрование полей в YAML
🔌 Загрузка из .yaml, .json, .env или dict
✅ Доступ к атрибутам (config.key) и ключам (config['key'])
🧰 CLI-интерфейс для рабочих процессов шифрования.

Пример использования:

from astarconf import Astarconf

conf = Astarconf("config.yaml")
print(conf.database.user)
print(conf["database"]["user"])

Ключ для шифрования/дешифрования может лежать в

  • переменной окружения ASTARCONF_SECRET

  • ~/.astarconf/secret.key

  • /etc/astarconf/secret.key

  • в файле secret.key в любом каталоге в $PATH доступном пользователю от имени которого запускается скрипт

astarconf.py -g ~/.astarconf/secret.key     # генерация секретного ключа
astarconf.py -c config.yaml                 # шифрование полей (по умолчанию
                                               - user, passowrd)
astarconf.py -c config.yaml token api_key   # шифрование конкретных указанных полей
astarconf.py -d config.yaml                 # дешифрование конфига (в тот же файл)
astarconf.py -d config.yaml -o output.yaml  # дешифрование конфига, 
                                              запись в  output файл
astarconf.py -o output.yaml -f              # перезапись output если существует

Модуль astarconf имеет несколько интересных особенностей, которые отличают его от omegaconf и dynaconf. Сравнение по ключевым аспектам:

1. Основные возможности:

Функционал

astarconf

omegaconf

dynaconf

Поддержка форматов

YAML, JSON, .env, dict

YAML, JSON (через OmegaConf)

YAML, JSON, TOML, .env, INI, py

Шифрование данных

Да (Fernet)

Нет

Да (частично, через Vault)

Доступ к данным

Атрибуты (obj.key) + индексы (obj["key"])

Атрибуты + индексы + точки (config.a.b.c)

Атрибуты + индексы

Динамическая загрузка

Нет (можно добавлять новые атрибуты),

Да (можно обновлять конфиг)

Да (динамическое перечитывание)

Валидация схемы

Нет

Да (через pydantic или dataclasses)

Да (через @validate)

Переменные окружения

Через .env

Через интерполяцию (${env:VAR})

Через envvar: или @env

Иерархическая конфигурация

Да (через AttrNamespace)

Да (вложенные структуры)

Да (многоуровневые настройки)

Плюсы моего модуля (astarconf):

Встроенное шифрование

  • Позволяет шифровать чувствительные данные (например, user, password) прямо в YAML/JSON.

  • omegaconf и dynaconf не имеют встроенного шифрования (в dynaconf есть поддержка HashiCorp Vault, но это внешний сервис).

Гибкий доступ к данным

  • Поддержка как obj.key, так и obj["key"].

  • В omegaconf тоже есть оба варианта, но в dynaconf предпочтительнее obj.key.

Простота использования

  • Ваш модуль легче освоить, так как он фокусируется на базовых задачах (загрузка + шифрование).

  • omegaconf сложнее из-за поддержки pydantic и интерполяции.

Когда использовать astarconf?

  • Если нужно простое решение с шифрованием (например, для хранения паролей в конфиге).

  • Если не нужна сложная валидация или динамическое обновление.

Когда выбрать omegaconf или dynaconf?

  • Если нужна интеграция с pydanticomegaconf.

  • Если нужна поддержка Vault или динамическое перечитывание конфигаdynaconf.

  • Если важна интерполяция переменных (например, ${env:DB_HOST}) → omegaconf.

Для моих быстрых задач мне вполне хватает astarconf

Например у меня есть словарь различных команд для разного оборудования, он гораздо больше примера

commands:
    "mac_addr_tbl_bymac":
        desc: 'show mac addres table and filter by mac'
        cisco_ios: 'show mac address-table | in {}'
        huawei_vrrp8: 'display mac-address | in {}'
        huawei_ce: 'display mac-address | in {}'
        eltex: 'show mac address-table | in {}'
    "mac_addr_tbl_byport":
        desc: 'show mac addres table on defined port'
        cisco_ios: 'show mac address-table interface {}'
        huawei_vrrp8: 'display mac-address {}'
        huawei_ce: 'display mac-address interface {}'
        eltex: 'show mac address-table | in {}'

а в конфиге программы fh (findHost) есть атрибут - путь до этого файла

dict_cmd_path: /some...path/commands.yml

а в коде использую например так
(в моем конфиге fh изначально отcутсвует атрибут commands):

import yaml
from astar import Astarconf

ac = Astarconf('/home/astar/mypython/fh.yml')
commands = {}

with open(ac.dict_cmd_path) as f:
    ac.commands = yaml.safe_load(f)['commands']

#и дальше объект представляющий всё наше оборудование myactivka
#имеет функцию получения информации с устройства
myactivka.getinfo(device, func, *args)
# где func - абревиатуры команды из commands.yml типа mac_addr_tbl_byport
port = 'Gi0/0/10'
#и код не зависит от того что такое device - huawei, cisco, eltex router or switch
command = ac.commands[func][dev['device_type']].format(port)

Если вам понравился такой подход к работе с конфигами

исходный код здесь: https://github.com/AstarAiki/astarconf

модуль на PYPi: https://pypi.org/project/astarconf/

установка: pip install astarconf

А больше всего хочется

Ваших отзывов и комментариев. Да, я изобрел велосипед, но по мне так удобный :-)

И я им пользуюсь!

Теги:
Хабы:
Всего голосов 1: ↑1 и ↓0+3
Комментарии0

Публикации

Работа

DevOps инженер
32 вакансии
Data Scientist
53 вакансии

Ближайшие события