Тип действия batch_playbook в политике
Обработка действия политики типа batch_playbook происходит следующим образом:
-
Сервис автоматизации создает две темы (subjects) в стриме брокера сообщений NATS:
-
В первую тему записывается информацию об объектах системы, которые необходимо обработать.
-
Во вторую тему скрипт обработки будет записывать информация об объектах, обработанных согласно бизнес-логике.
-
-
По завершении записи информации об объектах сервис автоматизации запускает скрипт или плейбук, который должен реализовывать следующие функции:
-
Чтение данных об объектах из первой темы NATS группами (батчами).
-
Обработка объектов согласно бизнес-логике.
-
Запись во вторую тему NATS данных об обработанных объектах.
-
По завершении обработки всех входных объектов — запись во вторую тему NATS пустого сообщения с заголовком, определенным в поле
finishEventHeaderдействия политики в схеме автоматизации.
-
-
Выполнение политики считается завершенным в следующих случаях:
-
Сервис автоматизации прочитал из второй темы NATS сообщение с вышеуказанным заголовком. Запуск политики будет помечен как завершенный успешно.
-
В течение времени, указанного в поле
msgTimeoutдействия политики в схеме автоматизации, в тему данных об обработанных объектах не поступило никаких данных. Запуск политики будет помечен как завершенный с ошибкой.
-
Ниже приведен пример реализации политики с действием типа batch_playbook и скриптов, реализующих обработку данных согласно вышеуказанному алгоритму.
Использование двух скриптов для выполнения действия типа batch_playbook не является обязательным. Например, вы можете объединить функции работы с NATS и бизнес-логику в один скрипт, который будет реализовывать вышеописанный алгоритм.
|
Пример настройки политики для выполнения действия типа batch_playbook
Пример политики
Пример представляет собой модификацию политики evo.vulnerability.policy.basic из примера в разделе Схемы автоматизации.
id: evo.vulnerability.policy.batch
type: calculation_schema
name: Политика создания задач на устранение уязвимостей с действием типа batch_playbook
tags: [vulnerabilities, policy, automation]
version: 1.0.0
status: stable
author: John Doe <johndoe@example.com>
policies:
- id: create_task_if_vulnerability_is_critical
name: Создать задачу, если уязвимость критическая
entity: vulnerabilities.rvision.ru/Vulnerability
conditions:
- type: expression
expression: 'equalText({field:criticalityLevel}, "Критический")'
actions:
- type: batch_playbook
playbook: create_tasks_from_critical_vulnerabilities
msgTimeout: 300000
Интерпретация примера
Схема содержит политику create_task_if_vulnerability_is_critical — автоматическое создание задач для уязвимостей с уровнем Критический:
-
Условие запуска политики типа
expressionсодержит выражение, которое возвращаетTrue, если уровень уязвимости — Критический. -
Действие политики — запуск скрипта
create_tasks_from_critical_vulnerabilitiesдля всех уязвимостей в системе. Скрипт завершает выполнение, если в течение 300 секунд после обработки последней уязвимости в систему не были добавлены новые уязвимости или сервис автоматизации получил из NATS сообщение с заголовкомX-Finish-Event.Заголовок
X-Finish-Eventиспользуется по умолчанию. Можно переопределить его, указав свойствоfinishEventHeaderв описании действия например:actions: - type: batch_playbook playbook: create_tasks_from_critical_vulnerabilities msgTimeout: 300000 finishEventHeader: "X-Last-Object"Соответствующий заголовок должен быть добавлен в финальное сообщение в скрипте, реализующем работу с NATS.
Пример скрипта, реализующего бизнес-логику
id: create_tasks_from_critical_vulnerabilities
type: script
name: Создать задачи из критических уязвимостей
tags: [vulnerabilities, policy, automation]
version: 1.0.0
status: stable
author: John Doe <johndoe@example.com>
source: !deno |
import { type Context, executeHandler } from '@expertise/policy_batch_action_handler_executor';
import { cms } from '@playbooks/sdk';
import type { PolicyChunkEventResult } from 'npm:@evo.cms/policy-module.contract@1.11.83';
import type { CmsObject } from 'npm:@evo.cms/policy-module.contract@1.11.83/dist/evo/object_mutation/v1/object_mutation';
export async function createTasksFromCriticalVulnerabilities(cmsObjects: CmsObject[]): Promise<PolicyChunkEventResult[]> {
await cms.mass_create({
domainId: 'tasks.rvision.ru',
entityId: 'Task',
valuesList: cmsObjects.map((cmsObject) => {
const values = JSON.parse(cmsObject.values!);
return JSON.stringify({
taskName: "Устранить уязвимость ".concat(values.name),
});
}),
});
return cmsObjects.map((cmsObject) => ({ policyChunkResult: { id: cmsObject.id } }));
}
export async function main(): Promise<void> {
const context: Context = JSON.parse(get_context());
await executeHandler({
handler: createTasksFromCriticalVulnerabilities,
batchSize: 1000,
context,
});
}
Интерпретация примера
Скрипт содержит следующие функции:
-
Функция
createTasksFromCriticalVulnerabilitiesиспользует функцию API скриптов для массового создания объектов (задач) в домене Задачи (tasks.rvision.ru). Наименование задачи составляется какУстранить уязвимость <name>, где<name>— наименование уязвимости. -
Функция
mainслужит точкой входа скрипта и вызывает функцию работы с NATSexecuteHandler, определенную в скриптеpolicy_batch_action_handler_executor.В функцию работы с NATS должен быть обязательно передан объект контекста выполнения скрипта, полученный с помощью функции get_context. Этот объект содержит имя стрима NATS, а также имена тем для чтения и записи информации об объектах системы.
Пример скрипта, реализующего работу с NATS
id: policy_batch_action_handler_executor
type: script
name: Массовая обработка объектов политики с помощью NATS
tags: [policy, automation]
version: 1.0.0
status: stable
author: John Doe <johndoe@example.com>
source: !deno |
import type { ConsumerMessages } from 'jsr:@nats-io/jetstream@3.1.0';
import { jetstream, jetstreamManager } from 'jsr:@nats-io/jetstream@3.1.0';
import { headers } from 'jsr:@nats-io/nats-core@3.1.0';
import { connect } from 'jsr:@nats-io/transport-deno@3.1.0';
import process from 'node:process';
import {
PolicyChunkEvent,
PolicyChunkEventFinish,
PolicyChunkEventResult,
} from 'npm:@evo.cms/policy-module.contract@1.11.83';
import type { CmsObject } from 'npm:@evo.cms/policy-module.contract@1.11.83/dist/evo/object_mutation/v1/object_mutation';
async function getCmsObjects(messages: ConsumerMessages): Promise<CmsObject[]> {
const cmsObjects: CmsObject[] = [];
for await (const message of messages) {
const policyChunkEvent = PolicyChunkEvent.decode(message.data);
if (policyChunkEvent.policyChunk && policyChunkEvent.policyChunk.object) {
cmsObjects.push(policyChunkEvent.policyChunk.object);
}
message.ack();
}
return cmsObjects;
}
export type Context = {
config: {
readSubject: string;
stream: string;
writeSubject: string;
};
};
export type ExecuteHandlerInput = {
handler: (cmsObjects: CmsObject[]) => Promise<PolicyChunkEventResult[]>;
batchSize: number;
context: Context;
};
export async function executeHandler(executeHandlerInput: ExecuteHandlerInput): Promise<void> {
const nc = await connect({
servers: [`${process.env.NATS_ADDR}:${process.env.NATS_PORT}`],
});
const js = jetstream(nc);
const jsm = await jetstreamManager(nc);
const ephemeralConsumerInfo = await jsm.consumers.add(executeHandlerInput.context.config.stream, {
filter_subject: executeHandlerInput.context.config.readSubject,
deliver_policy: 'all',
ack_policy: 'explicit',
});
const ephemeralConsumer = await js.consumers.get(
executeHandlerInput.context.config.stream,
ephemeralConsumerInfo.name,
);
while (true) {
const messages = await ephemeralConsumer.fetch({ max_messages: executeHandlerInput.batchSize });
const cmsObjects = await getCmsObjects(messages);
if (cmsObjects.length == 0) {
console.log('Стрим NATS полностью прочитан. Завершение чтения...');
break;
}
const policyChunkEventResults = await executeHandlerInput.handler(cmsObjects);
await Promise.all(
policyChunkEventResults.map((policyChunkEventResult) =>
js.publish(
executeHandlerInput.context.config.writeSubject,
PolicyChunkEventResult.encode(policyChunkEventResult).finish(),
),
),
);
}
const h = headers();
h.set('X-Finish-Event', 'true');
await js.publish(executeHandlerInput.context.config.writeSubject, PolicyChunkEventFinish.encode({}).finish(), {
headers: h,
});
await nc.close();
}
Интерпретация примера
Скрипт содержит следующие функции:
-
Функция
getCmsObjectsреализует чтение входной информации об объектах из NATS, их декодирование и отправку в NATS сообщения об успешном чтении (message.ack();). -
Типы
ContextиExecuteHandlerInputопределены для обеспечения корректного формата передачи входных параметров из скриптаcreate_tasks_from_critical_vulnerabilities. -
Функция
executeHandlerсостоит из следующих логических блоков:-
Подключение к серверу NATS с использованием системных переменных
NATS_ADDRиNATS_PORT. -
Создание потребителя (
consumer) для чтения сообщений из темы входных данных NATS. -
Чтение входных объектов из темы NATS в количестве
batchSizeза одну итерацию и их декодирование. Когда из темы не получено ни одного объекта, цикл прерывается и происходит переход к отправке финального сообщения. -
Обработка объектов функцией бизнес-логики
executeHandlerInput.handler, переданной в качестве аргумента из скриптаcreate_tasks_from_critical_vulnerabilities. -
Кодирование и запись в тему NATS объектов, полученных в результате работы функции бизнес-логики.
-
По завершении обработки — создание пустого сообщения NATS с заголовком
X-Finish-Event, его запись в тему NATS и закрытие соединения с NATS.
-
Была ли полезна эта страница?