Создание скрипта активного действия
Условные обозначения
OSD_HOME- домашняя директория Smart Monitor Web, обычно это/app/opensearch-dashboards/
Общие правила
Скрипт активного действия определяет пользовательскую логику обработки инцидентов и агрегаций в модуле Incident Manager.
Скрипты активных действий можно использовать как для инцидентов, так и для агрегаций. Скрипты выполняются вручную или при переходе инцидента в новое состояние рабочего процесса в качестве первичных или других действий.
Различия между первичными и другими действиями описаны в статье Активные действия.
Скрипты активных действий можно создавать на JavaScript (Node.js) и Python. Файл скрипта необходимо разместить в директории $OSD_HOME/plugins/smartMonitorIncidentManager/common/actions или $OSD_HOME/config/actions.
Скрипты из директории $OSD_HOME/config/actions сохраняются при обновлении плагинов. Скрипты из директории $OSD_HOME/plugins/smartMonitorIncidentManager/common/actions удаляются при обновлении.
У всех скриптов должны быть уникальные имена, иначе нужный скрипт может быть распознан некорректно.
После добавления файла скрипта перезапустите Smart Monitor Web, чтобы обновить каталог активных действий.
Ниже приведены данные, которые получает Python-скрипт. Скрипту на JavaScript передается тот же набор данных в виде аргументов функции. Подробнее см. в разделе Использование JavaScript.
Данные инцидента
При выполнении скрипта для инцидента в Python-скрипт передаются следующие данные. Если действие запускается вручную, sideEffects передается пустым объектом ("sideEffects": {}). Ниже в поле sideEffects показан пример заполненного объекта.
{
"doc": {}, // поля, которые нужно изменить в инциденте или агрегации
"user": {
"name": "admin", // имя пользователя
"backend_roles": [
// backend-роли пользователя
],
"roles": [
// роли пользователя
]
},
"incidentId": "zGQt4o8BqXcWBDa4I1DFGDH5", // ID инцидента
"index": ".incident-index-2023.21", // индекс, в котором хранится инцидент
"log": "", // логи инцидента (история изменения)
"metadata": {
"incidentId": "zGQt4o8BqXcWBDa4I1DFGDH5", // ID инцидента
"incidentTitle": "Exchange: антиспам пропустил письмо", // название инцидента
"incidentDescription": "Антиспам пропустил письмо", // описание инцидента
"index": ".smos_incident-2024.23", // индекс, в котором хранится инцидент
"urlToIncident": "https://smarthost.ru/incident-manager/...", // URL инцидента
"baseFields": {}, // значения полей карточки инцидента, указанных в настройке активного действия
"additionalFields": {}, // значения из блока «Дополнительные поля» в настройке активного действия
"fields": {
// дополнительные поля инцидента, установленные в активном действии
},
"reviewer": {
// ответственный за инцидент
}
},
"sideEffects": {
"status": {
"from": "open",
"to": "in_progress"
},
"assignedTo": {
"id": "sm_user",
"name": "Иван Иванов"
},
"fields": {
"severity": "high",
"category": "email_security"
},
"comment": "Инцидент принят в работу",
"actions": [
{
"type": "notification",
"channel": "email",
"recipients": ["admin@company.ru"],
"message": "Инцидент переведен в статус in_progress"
}
]
},
"target": "manual", // manual - флаг того, что используется активное действие или новый статус Рабочего процесса
"workflowId": "my-workflow", // ID Рабочего процесса инцидента
"_source": {
// тело инцидента
}
}
Данные агрегации
При ручном запуске скрипта активного действия для агрегации поле sideEffects передается в Python-скрипт как пустой объект:
{
"sideEffects": {}
}
Полный набор передаваемых данных:
{
"doc": {}, // поля, которые нужно изменить в инциденте или агрегации
"user": {
"name": "admin", // имя пользователя
"backend_roles": [
// backend-роли пользователя
],
"roles": [
// роли пользователя
]
},
"aggregationId": "zGQt4o8BqXcWBDa4I1DFGDH5", // ID агрегации
"index": ".incident_of_aggregation_results", // индекс, в котором хранится агрегация
"log": "", // логи агрегации (история изменения)
"metadata": {
"aggregationId": "zGQt4o8BqXcWBDa4I1DFGDH5", // ID агрегации
"aggregationTitle": "Exchange: антиспам пропустил письма", // название агрегации
"aggregationDescription": "Exchange: антиспам пропустил письма с архивом", // описание агрегации
"index": ".incident_of_aggregation_results", // индекс, в котором хранится агрегация
"urlToAggregation": "https://smarthost.ru//incident-manager/aggregations-result...", // URL агрегации
"baseFields": {
// значения полей для сравнения группы инцидентов, указанных в настройке активного действия
},
"additionalFields": {
// значения из блока «Дополнительные поля» в настройке активного действия
},
"comparation_fields": {
// значения полей для сравнения из агрегации
},
"functional_fields": {
// значения функциональных полей из агрегации
}
},
"sideEffects": {}, // при запуске активного действия передается пустой объект
"target": "manual", // manual - флаг того, что используется активное действие или новый статус Рабочего процесса
"workflowId": "my-workflow", // ID Рабочего процесса агрегации
"_source": {
// тело агрегации инцидентов
}
}
Поле sideEffects
При запуске активного действия поле sideEffects передается пустым объектом ("sideEffects": {}), как в примере выше для агрегации.
При выполнении активного действия в рамках перехода рабочего процесса поле target содержит новый статус, а sideEffects - списки скриптов:
{
"sideEffects": {
"pre": [
// имена скриптов, которые выполняются до изменения статуса
],
"post": [
// имена скриптов, которые выполняются после изменения статуса
],
"groupingPost": false // для массового перехода: выполнить post-действие один раз для группы инцидентов
},
"target": "in_progress"
}
Скрипты из sideEffects.pre выполняются до обновления инцидента или агрегации. После этого Incident Manager обновляет статус объекта, а затем выполняет скрипты из sideEffects.post.
Скрипты, выполняемые в режиме ручного запуска (target: "manual"), не могут напрямую изменять данные инцидента или агрегации.
Скрипт, который изменяет состояние или поля инцидента либо агрегации, необходимо использовать как первичное действие (pre-action) при переходе в новое состояние рабочего процесса.
Использование JavaScript
При создании активного действия на JavaScript используется следующий шаблон:
/** Функция для выполнения активных действий
* @param doc - поля, которые нужно изменить в инциденте или агрегации
* @param metadata - метаданные переданной сущности (агрегации или инцидента)
* @param entities - список инцидентов для `post-action` массового перехода рабочего процесса; при запуске активного действия передается пустой массив
* @param _source - неизмененный полный документ сущности (агрегации или инцидента)
* @param currentUser - текущий пользователь: { name, backend_roles, roles }
* @param index - индекс, в котором хранится сущность (агрегация или инцидент)
* @param log - логи сущности (история изменения агрегации или инцидента)
* @param sideEffects - действия при переходе между статусами
* @param target - флаг того, что используется активное действие или новый статус Рабочего процесса
* @param workflowId - ID Рабочего процесса сущности (агрегации или инцидента)
* @param incidentId - ID инцидента (передается в случае передачи инцидента)
* @param aggregationId - ID агрегации (передается в случае передачи агрегации)
* @param logger - функция логирования
*/
export default async (
doc,
metadata,
entities,
_source,
currentUser,
index,
log,
sideEffects,
target,
workflowId,
incidentId,
aggregationId,
logger
) => {
// тело функции
};
Параметры передаются непосредственно при вызове функции. Функция должна быть асинхронной для корректной работы и предотвращения преждевременного завершения выполнения.
Один JavaScript-файл можно использовать и в активных действиях, и в переходах рабочего процесса. Если скрипт используется как post-action и ему нужны currentUser или grouping, учитывайте порядок аргументов: (..., aggregationId, currentUser, logger, { grouping }).
Использование Python
При создании активного действия на Python используется следующий шаблон:
import json
class Object:
# вспомогательная функция для преобразования объекта в JSON
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=1)
""" Функция выполнения активных действий
@param: doc - поля, которые нужно изменить в инциденте или агрегации
@param: metadata - метаданные переданной сущности (агрегации или инцидента)
@param: incidents - список инцидентов для `post-action` массового перехода рабочего процесса
@param: user - текущий пользователь: { name, backend_roles, roles }
@param: index - индекс, в котором хранится сущность (агрегация или инцидент)
@param: log - логи сущности (история изменения агрегации или инцидента)
@param: sideEffects - действия при переходе между статусами
@param: workflowId - ID Рабочего процесса сущности (агрегации или инцидента)
@param: target - флаг того, что используется активное действие или новый статус Рабочего процесса
@param: incidentId - ID инцидента (передается в случае передачи инцидента)
@param: aggregationId - ID агрегации (передается в случае передачи агрегации)
@param: _source - неизмененный полный документ сущности (агрегации или инцидента)
"""
def my_func(doc, metadata, incidents, user, index, log, sideEffects, workflowId, target, incidentId, aggregationId, _source, grouping):
# код функции
print(json.dumps({"doc": doc})) # вернуть doc с полями, которые нужно изменить
if __name__ == "__main__":
_json = input() # данные считываются из потока через stdin
res = json.loads(_json)
my_func(
doc=res.get("doc"),
metadata=res.get("metadata"),
incidents=res.get("incidents", []),
user=res.get("user"),
index=res.get("index"),
log=res.get("log"),
sideEffects=res.get("sideEffects"),
workflowId=res.get("workflowId"),
target=res.get("target"),
incidentId=res.get("incidentId"),
aggregationId=res.get("aggregationId"),
_source=res.get("_source"),
grouping=res.get("grouping"),
)
Это один из возможных вариантов реализации. Можно использовать другие методы и функции.