Создание нового функционала для разработчиков¶
При разработке нового функционала со стороны администраторов тонких клиентов необходимо:
- Создать state/script с необходимой функциональностью;
- Протестировать работу state/script на стенде;
- Поместить файлы аналогично стенду в tkcontrol-configure/tkcontrol_configure/config/saltmaster;
- Обновить конфигурацию рабочего сервера.
При разработке нового функционала со стороны фронтендера web-приложения:
- Создать форму;
- Отправить POST запрос на /hosts или /groups.
Пример цикла разработки нового функционала¶
Создадим возможность отправлять пользователям уведомление с просьбой выключить компьютер.
Зайдем на тестовый стенд salt-master;
Добавим скрипт /srv/salt/states/files/notify-shutdown.sh, который будет выводить уведомление:
#!/bin/bash # Get xauthority location AUTH=$(ps aux | grep "\-auth " | head -n 1) AUTH=${AUTH/*\-auth /} AUTH=${AUTH/ */} # Declare zenity variables declare -x XAUTHORITY=$AUTH declare -x LC_ALL="ru_RU.utf8" declare -x DISPLAY=":0" title="Оповещение" text="Уважаемый пользователь, администратор просит выключить ваш компьютер!" zenity \ --info \ --title "$title" \ --text "$text" \ --width 500
Проверим работу скрипта:
sudo salt 'skupov-stagin-tkcontrol-client' cmd.script salt://files/notify-shutdown.sh
Добавим на фронтенд кнопку с вызовом этого скрипта:
<v-btn @click="sendShutdownNotify(hostname)"> Send shutdown notify </v-btn> ... async sendShutdownNotify(hostname) { await axios.post(`/api/${hostname}`, { salt_client: 'local_async', fun: 'cmd.script', arg: ['salt://files/notify-shutdown.sh'], }) }
Если все выполнилось удачно, переместим скрипт из salt-master /srv/salt/states/files/notify-shutdown.sh в tkcontrol-configure/tkcontrol_configure/config/saltmaster;
После сборки пакетов при конфигурировании salt-master наш скрипт установится:
sudo tkcontrol-configure salt-master
Пример цикла получения и сохранения данных в БД¶
Добавляем схему новой коллекции в tkcontrol-modules/tkcontrol_modules/eve/schemes. Создаем файл hosts_statuses.py со следующим кодом (обо всех вариациях схемы можно узнать на https://docs.python-eve.org/en/stable/config.html):
schema = { '_id': { 'type': 'string', 'unique': True, 'required': True, }, 'status': { 'type': 'string', 'required': True, 'allowed': ['up', 'down'], }, } hosts_statuses = { # По умолчанию используется паттерн для ObjectId, заменяем его любые непробельные символы 'item_url': 'regex("[\S]+")', 'schema': schema, }
В schemes/__init__ импортируем схему коллекции:
from .hosts_statuses import hosts_statuses
В dbadapter/tkcontrol_dbadapter/config/mongo_settings.py и в backend/tkcontrol_backend/config/mongo_settings.py зарегистрируем схему:
from tkcontrol_modules.eve.schemes import hosts_statuses ... DOMAIN = { ... 'hosts_statuses': hosts_statuses }
На данном этапе у нас есть возможность читать данные из backend и читать/создавать/изменять данные из dbadapter.
Добавим вызов команды в dbsync_service services/tkcontrol_services/services/dbsync_services.py:
# Отправляем команду раз в 600 секунд. if self._timer.time_to_refresh(600): self._salt_request(self._ping_request, request_name='ping')
Создадим фильтр services/tkcontrol_services/senders/filters/ping_filter.py для извлечения данных из salt events bus:
from .filter import Filter class PingFilter(Filter): def __init__(self): super().__init__() # Команда запускается от runnser_async self._allowed_types = ['run'] # Имя команды, которую мы выполняем self._allowed_functions = ['runner.manage.status'] # Нам важно только возращаемое значение self._allowed_statuses = ['ret'] # Мета информация для обновления/создания документов self._db_tag = { 'method': 'patch', # Изначально пытаемся обновить данные 'collection': 'hosts_statuses', # Имя коллекции 'force': True, # Если запись не получается обновить (ее не существует), тогда мы создаем запись } # Перед вызовом этой функции Sender устанавливает значение обрабатываемого сообщения в self._ev_msg def process(self): # Извлекаем данные из salt event up_hostnames = self._ev_msg.data['return']['up'] down_hostnames = self._ev_msg.data['return']['down'] # Формируем полезные данные для выгрузки в бд. Best practice вывести логику по обработке в отдельный сериалайзер, для примера смотрите key_filter payloads = [] for hostname in up_hostnames: payloads.append({ 'data': {'_id': hostname, 'status': 'up'}, 'lookup': hostname, }) for hostname in up_hostnames: payloads.append({ 'data': {'_id': hostname, 'status': 'down'}, 'lookup': hostname, }) return self._db_tag, payloads
Покроем фильтр тестами. Смотрим аналоги в services/test/senders/filters/test_key_filter;
Добавим фильтр в сборку приложения services/tkcontrol_services/app:
def create_events_bus_service(config, salt_api) -> Service: ... ping_filter = PingFilter() ... db_sender.add_filter(ping_filter)
После перезапуска dbadapter, backend, services сервисы начнут собирать и сохранять данные в dbadapter, а backend сможет эти данные отображать.