#1157: Написание плагинов для автоматизации действий на Python

ВЫ ИСПОЛЬЗУЕТЕ МЕХАНИЗМ СКРИПТОВ, КОТОРЫЙ ЗАПУСКАЕТСЯ ОТ ИМЕНИ ROOT БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ,
НА ВАШЕ УСМОТРЕНИЕ. ЛИЦЕНЗИАР ЯВНО ОТКАЗЫВАЕТСЯ ОТ ВСЕХ ГАРАНТИЙ, ЯВНЫХ, ПОДРАЗУМЕВАЕМЫХ ИЛИ
УСТАНОВЛЕННЫХ ЗАКОНОДАТЕЛЬСТВОМ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ПОДРАЗУМЕВАЕМЫМИ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И НЕНАРУШЕНИЯ ПРАВ.

В ПОЛНОЙ МЕРЕ, РАЗРЕШЕННОЙ ЗАКОНОМ, ЛИЦЕНЗИАР НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА КОСВЕННЫЕ, СЛУЧАЙНЫЕ,
СПЕЦИАЛЬНЫЕ, ПОСЛЕДУЮЩИЕ УБЫТКИ ИЛИ УБЫТКИ В ВИДЕ УПУЩЕННОЙ ВЫГОДЫ ИЛИ ВЫРУЧКИ, ВОЗНИКШИЕ ВСЛЕДСТВИЕ ИЛИ СВЯЗАННЫЕ С ДАННЫМ СОГЛАШЕНИЕМ ИЛИ ВАШИМ ИСПОЛЬЗОВАНИЕМ МЕХАНИЗМА.

Введение

Движок скриптов позволяет вам писать и использовать произвольный код Python для запуска автоматизаций,
инициируемых событием, по расписанию или даже вручную пользователем через веб-форму.

Загружать скрипты и настраивать их запуск через Веб-форму, Действия по событию, Действия по расписанию могут администраторы системы в разделе Настройки > Автоматизация и маршрутизация > Скрипты

Вопросы безопасности и производительности

Скрипты выполняются внутри контейнера, поэтому у них нет доступа к аппаратному узлу / виртуальной машине,
на которой установлена Swarmica.
Однако сценарии имеют доступ к общим разделам диска и основной базе данных, используемой Swarmica,
поэтому будьте осторожны при выполнении потенциально опасных операций, таких как удаление и изменение
любых данных или файлов.

Кроме того, ресурсы памяти/процессора используются совместно со всем инсталляцией Swarmica, поэтому
настоятельно рекомендуется минимизировать импорт библиотек и модулей до только необходимого
минимального набора функций.

Например, вместо импорта всего модуля import datetime импортируйте только необходимую вам функцию:
from datetime import timedelta.

Обзор движка времени выполнения

Есть несколько способов запуска сценария:

[Триггер события] ---> +context --\
                                  \
[Расписание] --------> +context----\
                                    >----> Runner.run(kwargs={data: **params, **context})
[CLI] -------------> +params-------/
                                  /
[API/WEB] ---------> +params-----/

Итак, в основном, если сценарий времени выполнения запускается Триггером События или по Расписанию,
то данные события и пользовательские контекстные данные, настроенные в соответствующем триггере /
расписании, передаются в параметры сценария.

Допустим, сценарий запускается событием UserEvent, тогда контекст можно разобрать следующим образом:

class Runner(BaseRunner):
    def run(self, *args, **kwargs):
        data = kwargs.get('data', {})
        if not data or 'event_id' not in data:
            logger.error(f"No event_id passed, exiting")
            return
        event = UserEvent.objects.filter(id=data['event_id']).first()
        if not event:
            logger.error(f"No event with {data['event_id']} found, exiting")
            return

Если мы настроим Триггер События на передачу дополнительного контекста в скрипт, например, списка
email-адресов для получения оповещения при изменении учетной записи пользователя, то он также будет
передан в скрипт.

При условии, что пользовательский контекст Триггера События выглядит так:

{
  "recipients": [
    "user1@domain.tld",
    "user2@domain.tld"
  ]
}

Теперь вы можете получить доступ к значению переменной внутри скрипта следующим образом:

data = kwargs.get('data', None)

if data:
    recipients = data.get('recipients', None)

Вы также можете настроить скрипт так, чтобы у него была собственная веб-форма, которая может принимать,
проверять и передавать параметры в скрипт.

Допустим, мы пишем скрипт, который генерирует пользовательский отчет в Excel и отправляет его списку
email-получателей. И мы хотим, чтобы пользователи передавали даты начала и окончания отчета и список
получателей, разделенный запятыми.

В веб-интерфейсе Swarmica в настройках скрипта мы настраиваем следующие параметры веб-формы:

[
  {
    "name": "start_date",
    "type": "datetime",
    "readonly": false,
    "displayName": "Report start date"
  },
  {
    "name": "end_date",
    "type": "datetime",
    "readonly": false,
    "displayName": "Report end date"
  },
  {
    "name": "recipients",
    "type": "text",
    "displayName": "Comma-separated recipients"
  }
]

Теперь мы можем получить доступ к этим параметрам в скрипта следующим образом:

params = kwargs.get('data', {})
if params:
    if 'recipients' in params:
        recipients = params.get('recipients')
        if recipients:
            recipients = [x.strip() for x in recipients.split(',') if '@' in x]
        if not recipients:
            logger.info("Input error: empty/invalid list of 'recipients' specified")
            return
        
        start_date = params.get('start_date', None)
        if isinstance(start_date, str) and start_date.strip():
            report_start_date = parse_datetime(start_date)
            
        end_date = params.get('end_date', None)
        if isinstance(end_date, str) and end_date.strip():
            report_end_date = parse_datetime(end_date)

        if not report_end_date:
            report_end_date = now().replace(hour=23, minute=30, second=0, microsecond=0).replace(tzinfo=default_time_zone)
        if not report_start_date:
            report_start_date = report_end_date - timedelta(days=1)

Доступ к объектам Swarmica

Обычно вам нужно манипулировать моделями и наборами запросов (querysets) для объектов Swarmica в
ваших скриптах.
Поскольку Swarmica использует Django в качестве фреймворка, большинство методов моделей и наборов
запросов также работают здесь.

Смотрите полную справку по методам моделей Django и наборов запросов на официальном сайте документации:

Querysets

Models

Большинство объектов, которые вам могут понадобиться, находятся в пакете core, за исключением объектов
User - они находятся в пакете swarmica_auth.

Также вам, как правило, потребуется импортировать общие константы, используемые Swarmica,
следующим образом:


from swarmica import defs

print(defs.USER_ROLES_INTERNAL)

Давайте рассмотрим некоторые типичные операции в действии.

Работа с набором Заявок (Tickets)

Давайте выведем ID заявки, тему и имя назначенного исполнителя для всех новых и открытых заявок,
созданных между указанными датами начала и окончания:


from swarmica import defs
from core.models import Ticket

class Runner(BaseRunner):
    def run(self, *args, **kwargs):
        params = kwargs.get('data', {})
        if not params:
            return
            
        start_date = params.get('start_date', None)
        
        if isinstance(start_date, str) and start_date.strip():
            report_start_date = parse_datetime(start_date)
        end_date = params.get('end_date', None)
        
        if isinstance(end_date, str) and end_date.strip():
            report_end_date = parse_datetime(end_date)

        if not report_end_date:
            report_end_date = now().replace(hour=23, minute=30, second=0, microsecond=0).replace(tzinfo=default_time_zone)
        if not report_start_date:
            report_start_date = report_end_date - timedelta(days=1)
            
        tickets = Ticket.objects.filter(created_at__range=(report_start_date,report_end_date), 
                                        status__in=[defs.TICKET_STATUSES_NEW, defs.TICKET_STATUSES_OPEN])
        
        for ticket in ticket:
            print(f"#{ticket.id}: {ticket.subject} ({ticket.assignee.name})")

Работа с Пользователями

Давайте отключим все email-уведомления для заблокированных пользователей:

from swarmica import defs
from swarmica_auth.models import User

class Runner(BaseRunner):
    def run(self, *args, **kwargs):
        
        users = User.objects.filter(role=defs.USER_ROLES_BLOCKED)
        
        for user in users:
            user.email_notifications.clear()

Доступные сторонние библиотеки:

Ряд предустановленных библиотек доступен для импорта и использования в ваших скриптах.
Смотрите список доступных методов в документации соответствующей библиотеки:

import re               # Для работы с регулярными выражениями
import os               # Для работы с вещами ОС, такими как пути к файлам и т.д.
import bs4              # Для парсинга HTML, XML и т.д. с помощью BeautifulSoup
import csv              # Для чтения и записи CSV
import json             # Для парсинга JSON
import time             # Для работы с текущим временем, например, генерации временных меток
import pandas           # Для работы с наборами данных
import urllib           # Для парсинга и записи параметров URL, urlencode и т.д.
import dateutil         # Для работы с датами, например, парсинга даты из строки
import datetime         # Для работы с объектами datetime, например, вычисления длительностей и т.д.
import openpyxl         # Для чтения и записи Excel
import requests         # Для работы с удаленными API и вебхуками

Шаблон скрипта

Скачать шаблон sample.py