Разработка сервиса, позволяющего осуществлять настройку компонентов операционной системы, предоставляющего удобный универсальный интерфейс для интеграции в существующие решения и реализации своих собственных.
Created attachment 1790 [details] Архитектура settingsd
Created attachment 1791 [details] Схема взаимодействия компонентов settingsd
В результате обсуждения с sin@ разработали концепцию необходимого сервиса. Рабочее название системы - settingsd (если никто не против :-) ). Для начала, нам необходимо расширяемое средство с удобным конечным интерфейсом, позволяющим интегрировать это средство в существующие решения. Например, KDE control Center, Гномовские программы и прочее. Так же необходимо иметь инструмент командной строки для работы с этой системой, возможность подключения веб-интерфейса и управления группами серверов по сети. После обсуждений решили, что такое средство должно состоять из сервиса, который, с одной стороны, имеет подключаемые модули для выполнения каких-то настроек, с другой стороны, предоставляющий интерфейс через D-Bus. Такое решение обусловлено тем, что практически все современные интерфейсы настроек имеют возможность принимать методы D-Bus, в отличие от, например, Alterator, который реализует свой собственный интерфейс для коммуникаций. На рисунке http://bugs.etersoft.ru/attachment.cgi?id=1790 показано, как выглядит, в нашем предположении, такая система настроек. Она состоит из сервиса, реализующего, собственно, настройки и выдающего в конечном итоге D-Bus API для их выполнения. Используя этот интерфейс, мы можем создать как утилиты командной строки (блок CLI), веб-интерфейс (блок WEB), так и интегрировать его в существующий средства управления машиной. Отдельным пунктом есть блок NET, выполненный в виде отдельного сервиса, который инкапсулирует сообщения D-Bus в сеть (возможно, через Ice) для того, чтобы можно было удаленно выполнять настройки сразу на нескольких машинах с помощью некого централизованного интерфейса. Например, таким образом можно применять групповые политики для серверов, или скопом менять настройки, скажем, сети, на всех машинах. Сервис в свою очередь представляет собой небольшую программу, к которой подключаются два типа модулей. Первый тип (FM, Functional Module), представляет из себя модуль, реализующий низкоуровневую функцию, например, установку айпишника, создание группы пользователей и тп. Второй тип модулей (AM, Action Module) использует модули FM для выполнения неких действий. Например, настройка Samba будет зависеть от монтирования каталогов, создание групп и пользователей. Эта зависимость отражена в приложении http://bugs.etersoft.ru/attachment.cgi?id=1791 . Сервис сначала загружает модули FM, читая их реквизиты (что они умеют, какое апи содержат и т.п.), затем использует эту информацию при загрузке модулей AM, которые, используя известное API модулей FM, выполняют последовательность действий и точно так же выставляют свое API. Сервис, используя информацию от модулей AM, конвертирует ее в вызовы D-Bus, которые и выставляет в операционную систему. Кроме высокоуровневых сервисов AM, таких как "Установить samba", "Добавить пользователя" сервис может выставлять и API модулей FM, "Создать группу", "Смонтировать каталог" и т.д. Используя предоставленное API D-Bus, другие программы смогут выполнять определенные действия в ОС. Как я уже писал выше, можно инкапсулировать это API в сеть, таким образом организовать централизованное управление серверами. Кроме того, такой подход позволит заменить собой такие кривые штуки, как NetworkManager, просто реализовав их D-Bus`ное API. Пользовательские программы и существующие апплеты не увидят, что непосредственно сервис на системном уровне был подменен более правильной конструкцией, это позволит не ломать совместимость и уже устоявшийся набор приложений в десктопах.
Читал документацию по D-Bus.
Прочитал: http://ru.wikipedia.org/wiki/D-Bus http://knotes.ru/2009/05/d-bus-tutorial/ http://www.linux.org.ru/wiki/en/D-Bus http://www.linux.org.ru/wiki/en/HAL http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.htm http://www.redhat.com/magazine/003jan05/features/dbus/ http://wiki.python.org/moin/DbusExamples http://paste.lisp.org/display/45824 http://en.wikibooks.org/wiki/Python_Programming/Dbus http://effbot.org/librarybook/configparser.htm http://docs.python.org/library/configparser.html http://habrahabr.ru/blogs/python/46306/ http://habrahabr.ru/blogs/python/72757/ http://www.ibm.com/developerworks/ru/library/l-pycon/index.html http://www.linux.org.ru/wiki/en/HAL Начал реализовывать базовую архитектуру сервиса.
Реализовал первый прототип, пробрасывающий функции модулей в D-Bus. Выполнил в виде библиотеки декораторов. Реализация оказалась не слишком удачной, так как я использовал метаклассы для создания объектов D-Bus и динамически цеплял к ним методы. Такой подход работает, но, как оказалось, не работает интроспекция методов, которые так же строятся на основе декораторов, но уже из dbus.service. Немного изменил подход, делаю на основе статических классов.
Получилась реализация с классами. Решение, в принципе, достаточно красивое. Есть набор библиотек, базовых классов и декораторов, которые предоставляют модулям высокоуровневый интерфейс. Программа импортирует модули, используя их классы строит дбасный интерфейс.
В текущей реализации на основе библиотеки классов, пока что не совсем понятно, как задавать настройки для класса сервиса. Пробую два решения - на основе декораторов класса и на основе переопределения __init__(). Хотелось бы такой реализации, при которой не пришлось бы много раз перечитывать конфиги. Экспериментирую с классом сервиса.
Сделал реализацию, в которой добавлен еще один слой абстракции - сервис. Теперь при импортировании модуля делается экземпляры этого класса, который, в свою очередь, динамически создает экземпляры объекта интерфейса. Такой способ позволит создавать абстракции, наподобие тех, что реализует networkmanager (http://people.redhat.com/dcbw/NetworkManager/NetworkManager%20DBUS%20API.txt). Готовый прототип находится здесь: git.eter:/people/mdevaev/packages/settingsd.git По исходникам можно примерно понять, как будет развиваться API пакета.
Начал реализовывать другие компоненты библиотеки, такие, как загрузчик конфигов. Делаю более правильный основной модуль: он должен реагировать на сигналы, в том числе на SIGHUP - перечитывать конфиги.
Сделал загрузчик конфигов с проверкой на правильность опций. Переписал структуру классов без использования передачи родителя. Получилось гораздо проще и универсальнее. Начал писать модуль для ведения системных логов, а так же интроспекции свойств объектов (не путать с дбасной). Нужно это для того, чтобы предполагаемый UI мог получить описание методов и для чего они нужны.
Добавил в конфиги валидатор, сделал разделение на типы модулей AM и FM. Между ними нет особой разницы: каждый из них отображается в dbus. Но FM инициализируется первым, давая возможность AM использовать себя через специальный внутрисервисный интерфейс. Модули обоих типов могут так же содержать конфигурационные файлы, загрузчик конфигов так же будет проверять правильность указываемых опций для них.
Создал библиотеку валидаторов для различных типов переменных и параметров. Сделал основной модуль программы в виде класса приложения, который содержит в себе все необходимые функции для инициализации, запуска и слежения за модулями. Туда же добавлю обработчики сигналов. Написал базовые функции модуля для ведения логов и вывода сообщений. В планах прикрутить syslog. Добавил возможность отладки вызовов dbus: в лог пишется функция, которая была удаленно вызвана, ее аргументы и возвращаемое значение. Благодаря этому теперь упроститься задача написания новых модулей и адаптация интерфейсов, например, от NetworkManager.
Добавил в модуль логов деление на классы сообщений. Немного оптимизировал отладочный вывод трейсового декоратора.
В Application помещен полный код запуска. Добавил API для динамической работы с объектами D-Bus и классами в рантайме. Это позволит реализовать добавление и удаление элементов, таких, как сетевые интерфейсы NetworkManager. Объединил реквизиты плагина и сервисный класс в один класс с двумя интерфейсными родителями. Отладочный декоратор сохраняет метод __doc__ для интроспекции. Исправил несколько ошибок в логгировании, добавил возможность записи в логи исключений с полным трейсбеком. Начал реализовывать средства, которые позволит управлять процессом сервиса (будет форкаться от основного при settingsd -s, убиваться при settingsd -k.
Вдумчиво читал http://www.python.org/dev/peps/pep-0318/ и http://docs.python.org/library/traceback.html .
Реализовал корректную поддержку ухода settingsd в фон.
Добавил короткие псевдонимы для функций логгирования. Разделил загрузку конфигурационных файлов на две стадии: сначала собственные конфиги, затем конфиги модулей. Это позволило реализовать переназначение основных параметров через опции командной строки. Добавил модуль для управления демоном, его запуск и останов. Добавил поддержку опций командной строки и возможностью выбора режима запуска (интерактивно или демоном). Отрефакторил некоторые модули. Добавил модуль для контроля запуска сервиса. Вместо использования _exit(1) модуль демона генерирует исключения.
Для использования плагинов при локальном запуске не требуется прописывать sys.path.append(".."), удалил. Так же удалил рекурсивное импортирование модуля const. Добавил цветовую раскраску логов при выводе stderr на терминал. Опция в конфиге прилагается. Ее значение логически умножается с isatty(2). Строки, содержащие в себе символ \n, разбиваются на несколько и записываются отдельными элементами в syslog и терминал. Добавил возможность трассировки сигналов D-Bus (раньше были только методы) при отладке, кроме того, теперь при трассировке, возникающие исключения, являющиеся некорректным вызовом функций извне, записываются в логи. Раньше они отправлялись сообщением вызывающему. Сейчас идут и туда, и в лог. Реализовал экспериментальный модуль управления внутренними функциями settingsd. Выяснилась проблема с конфликтом имен модулей при импортировании, если модуль находимтся в sys.path+["путь/к/плагинам"]. Существует два решения: именовать модули с префиксом, например, sdmod_settingsd.py, второе - использовать функции из модуля imp (http://docs.python.org/library/imp.html). Мне больше нравится второе, так как оно избавляет от потенциальных ошибок при разработке расширений.
Провел реструктуризацию кода для лучшей сопровождаемости. Сделал экспериментальный модуль функций контроля самого сервиса. Сейчас можно менять уровень логов и выполнять завершение работы через DBus. Полностью переделал модель shared-объектов, теперь он имеет иерархическую структуру, которая позволяет делать объекты скольки угодно уровней вложенности. Сделал API для построения дерева объектов. Очевидно, так же необходим некий механизм, который позволит объекту узнать, в каком месте дерева он вообще находится. Пока сделал это с помощью передачи строк вручную, сейчас работаю над функциями организации родителей объекта.
Сделал нормальную иерархическую структуру, теперь возможно получить путь внутри shared-структуры, имя компонента и имя шары, в которой он находится.
Добавил поддержку сигнатур в методы и сигналы. Теперь работает передача вообще любых параметров для оригинальных декораторов D-Bus (http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html). Исправил ошибку, приводившую к выводу в syslog управляющих escape-последовательностей. В модуле логов вынес константы с текстовым значением ошибок из функции log в пространство имен модуля. Отрефакторил. Добавлена поддержка макросов в строках, переданных для логгирования. Макрос "{time}" заменяется на текущее время, "{mod}" - на имя модуля, вызвавшего функцию логов. Сервер при старте пишет более подробно сообщения, вплоть до uid, cwd и umask процесса.
Написал на wiki страницу со стадиями разработки: http://wiki.office.etersoft.ru/ASU/Boxy/DevelopmentStages
Добавил в модули контроля settingsd, example, system_services_config описания сигнатур методов, привел в порядок код плагинов. Исправил багу в валидаторе значения из списка. Более подробные сообщения при инициализации сервисов. Мелкие багфиксы. Изучал код System Tools Backends: http://system-tools-backends.freedesktop.org/
Более информативные сообщения модулей о сбое дочернего процесса. Нужное перестать зашивать полные пути к бинарникам в код, а использовать просто имя программы. С другой стороны, такие утилиты, как chkconfig находятся в /sbin, и в PATH sbin-пути не прописаны. Сам settingsd при этом умеет работать в юзерспейсе. Одно из решений, как я полагаю, заключается в добавлении в PATH серверного процесса нужных путей.
Добавил в модуль информации о системе функцию получения аптайма.
Изменил расположение библиотек в проекте, добавил соответствующий код. Добавил недостающие каталоги. Добавил .gitignore для игнорирования pyc-файлов в проекте.
Исправил проблему с нахождением процесса-демона при системном запуске. Исправил ошибку с убиванием системного демона. Изменил компоновку пакета для упрощения инсталляции и отладки. По умолчанию конфиг настроен на системный запуск. Для локального запуска теперь надо использовать команду: "python settingsd-server.py --bus-type=session --log-level=2". Исправил ошибку в парсере опций командной строки, добавил опции и функцию для отображения состояния демона.
Обнаружил багу, связанную с отсутствием прав доступа к публичным методам на Альте при запуске на системной шине. На Федоре работает нормально.
Баг с доступом был ложной тревогой, я неправильно написал обращение к функции. Интересно, что в Альте запрет на функции работает несколько иначе: вместо сообщения о невозможности вызова, не происходит вообще ничего. Исправил несоклько багов, связанных со сборкой пакета. Немного непонятно считается загрузка на ядро процессора. Видимо, нужно взять функции из исходников top, потому что, видимо, информация в манах не соответствует действительности.
В коде классов используются закрытые переменные вместо приватных. Исправил несколько небольших ошибок, связанных с отображением логов.
Исправил баг с определением пути объекта. Тип возвращаемого значения meminfo изменен с float на int.
Сервер выводит более подробные сообщения при загрузке и выгрузке модулей Добавлен валидатор для строкового списка
Переделан анализ списка макросов в logger, добавлен макрос {submod}. Добавлен собирательный модуль tools, в него помещена общая функция выполнения процесса execProcess(). Все функциональные модули теперь используют общие исключения и общуюю реализацию tools. Правка незначительных ошибок.
Добавлено исключение при инициализации списка сервисов при сбое исполняемого файла. Исправлен баг с получением словаря в sharedObjects().
Включена поддержка потоков для GObject. Удалены импорты неиспользуемых модулей. Динамическое создание и удаление сервисов по событиям inotify для /etc/rc.d/init.d и дополнительный сигнал об этом изменении. Так же изменен способ загрузки сервисов - вместо chkconfig по содержимому каталога.
Добавлена политика для fmod_disks_smart, позволяющая просматривать его параметры любому пользователю. Дополнительные константы версии, представляющие текущий уровень функциональности (интовое число) и статус разработки. Классификаторы при установке формируются динащмчески с использованием settingsd/const.py Дополнительное API для определения по DBus уровня функциональности демона для обеспечения совместимости интерфейсов. Большой рефакторинг, обработка исключения и логгирования вывода дочерних процессов перенесена в функцию execProcess, это позволило сократить код исполнения процесса в функциональных модулях до одной-двух строк.
Собрал в пакет settingsd-0.1-alt6.
Собрал новую версию с учетом дополнительных зависимостей.
Подправил регэкспы в модулях fmod_date_time и fmod_ntp_config, теперь они более правильно обрабатывают текст в конфигах. Обновил права доступа dbus, удалил лишние правила. Установил новый уровень функциональности.
Собрал новую версию settingsd-1.0-alt9 с новыми зависимостями и модулями.
В плагинах, при ошибке внешней программы, вызванной через tools.execProcess(), теперь отсылается ее код возврата, а не исключение. Добавил валидатор для адресов IPv4.
Исправил небольшую ошибку в валидаторе адресов IPv4. Добавил валидатор сетевой маски IPv4. Поддерживается как строковый формат с октетами, так и одночисленный (например, 24) формат записи. Добавил валидатор для MAC-адресов.
Переписал парсеры для ntp_config. Теперь происходит замена переменных прямо в тексте, а не добавление в конец, что позволит сохранить актуальные комментарии в файлах.
Обновил правила D-Bus для поддержки новый модулей. Поднял уровень функциональности. Пакет разделен на несколько: основная программа с базовыми модулями и дополнительные модули настройки сервисов (типа smart, ntp, dnsmasq). Добавил каталоги, в которых плагины могут хранить неизменяемые данные: /usr/share/settingsd/data/{functions,actions,customs}. Пофиксил ошибки сборки. Собрал новую версию пакетов: --------------------- settingsd-fmod-dnsmasq-config-0.1-alt12 settingsd-fmod-disks-smart-0.1-alt12 settingsd-fmod-ntp-config-0.1-alt12 settingsd-0.1-alt12 ---------------------
Добавил возможность копирования конфигурации по умолчанию для модулей dnsmasq, ntp и времени.
Исправил несколько ошибок в пространствах имен. Написал модуль для настройки rtorrentd, добавил соответствующий пакет в спек.
Добавил политики D-Bus для fmod_rtorrentd_config. Поднял functionality_level = 83
Обновил правила, поднял уровень функциональности, собрал пакет 0.1-alt14
Разделил валидаторы в пакет validators с отдельными модулями Запускалку дочерних процессов и методы специальной работы с dbus перенесены в пакет tools. Все модули были адаптированы для использования с новой версией библиотек. При получении прерывания с клавиатуры выводится предупреждение. Модифицировал установщик под новую структуру программы. Собрал версию 0.2-alt1
В модулях, осуществляющих редактирование файлов, существует значительная часть дублирующегося кода разбора конфигов. Нужна библиотека для редактирования "плоских" конфигурационных файлов (без секций, не как ini) с сохранением комментариев и возможностью гибкой настройки разделителей, пробелов и прочих параметров разбора. На данный момент реализовал универсальный класс в возможностью чтения. Запись пока что не до конца отлажена.
Исправил несколько багов в парсере, продолжение реализации класса.
Парсер готов, нужно перевести все модули на его использование.
Возникли проблемы в парсере при перезаписи множественных значений одной переменной. Исправлял ошибку, пришлось полностью переписать функцию установки значения.
Наконец получилось написать нормальный редактор конфигов. Собственно, нужно было это потому, что старые парсеры некорректно обрабатывали экранирование, комментарии и групповые параметры (когда одна переменная могла иметь несколько значений). В новом персере все переменные при замене находятся на своих местах, в случае замены группы удаляются все экземпляры переменных и создается новая на месте последнего появления. Можно гибко настраивать раздлелители, пробелы, виды комментариев для того, чтобы редактировать разные типы плоских конфигов. Сейчас буду переносить на и использование следующие модули: fmod_date_time.py fmod_dnsmasq_config.py fmod_ntp_config.py fmod_rtorrentd_config.py
В PlainEditor разделены фазы открытия файла для записи и чтения из него. Теперь при открытии файл кэшируется и открывается только тогда, когда требуется произвести запись. Раньше файл открывался в режиме r+ и не получилась из-под пользователя использовать системные конфиги из-за отсутствия доступа на такой режим. Добавлено логгирование действий и некритичных исключений при создании пустого файла или из семпла. Все модули из предыдущего сообщения переведены на использование PLainEditor, оный ими и протестирован.
Собрал новую версию 0.3-alt1 (релиз поднят из-за обширности изменений в API библиотеки)
Новый модуль валидаторов os, предоставляющий проверки для общих юниксовых сущностей. Сейчас там проверка на валидность имени группы и пользователя. Рефакторинг некоторых модулей.
Обновил политику fmod_system_services, небольшой рефакторинг кода
Исправил вызов сигналов servicesChanged() из fmod_system_services и groupsChanged() из fmod_local_groups. Для поименно-выставляемых объектов добавил метод realName() отражающий настоящее (не приведенное к правилам D-Bus) имя.
Исправлена ошибка, приводящая к исключению при закрытии PlainEditor.
Изменил наименования опций настройки на более короткие во всех модулях, уровень функций установлен в 121
fmod_local_users и fmod_local_groups включены в состав основного пакета. Несколько исправлений ошибок в PlainEditor, доработка метода установки значения. Теперь он принимает аргумент None. В модулях, динамически обновляющихся их конфигураций по inotify реализована корректная обработка ошибок открытия файлов. Обновление спека, политик D-Bus, уровень функциональности = 132.
Собрал новую версию. В функциональных модулях нормализация имен d-bus теперь выполняется регулярным выражением. Для редактирования конфигурации samba требуется реализовать поддержку редактирования ini-файлов. Проделана начальная работа в эту сторону, изучены возможности использования сторонних либ.
Написал редактор ini-файлов, отдельный от PlainEditor, так как доработка последнего привела бы к перегрузке и нечитабельности кода.
Редактор INI-файлов правильно вставляет в секции новые опции, в прямом порядке. В функцию execProcess() добавлена возможность указывать строку со стандартным вводом, который передается выполняемому процессу. Для execProcess() добавлен режим конфиденциальноси стандартного ввода. Это сделано для того, чтобы в логах не появлялись приватные данные пользователя, например, пароли,ю при возникших в результате работы исключениях. Режим устанавливается флагом и работает всегда, кроме случая, когда уровень логгирования settingsd установлен в отладку. В связи с новой реализацией execProcess() пришлось заменить код, ее использующий, во всех модулях. Попутно были исправлены незначительные ошибки, приводящие к неверному возвращаемому значению из внешнего API модулей.
Откладываем задачи, к которым не обращались более 100 дней.