Top.Mail.Ru
Tdg » 1.6 » 1. Руководство по разработке приложений » 1.2. Безопасная среда исполнения
 
1. Руководство по разработке приложений / 1.2. Безопасная среда исполнения
1. Руководство по разработке приложений / 1.2. Безопасная среда исполнения

1.2. Безопасная среда исполнения

1.2. Безопасная среда исполнения

Пользовательский код в TDG исполняется отдельно от собственного кода TDG – в безопасной изолированной среде, называемой песочницей (или sandbox). При этом используется JIT-компилятор LuaJIT.

Для доступа к данным, хранящимся в TDG используйте функции (программного интерфейса репозитория). Все остальные функции и возможности, которые можно использовать при написании пользовательского кода обработки в песочнице, описаны в данном разделе.

Все функции можно разделить на следующие категории:

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

Важно

Подключать новые функции к безопасной среде исполнения категорически запрещено для сертифицированной версии TDG. Перед подключением новых функций в обычной версии TDG рекомендуется самостоятельно проверять их на уязвимости.

1.2.1. Стандартные модули и функции

Общедоступные Lua модули и функции:

  • assert – вызывает исключение, если первый аргумент является nil или false;
  • math – интерфейс стандартной математической библиотеки C;
  • next – возвращает следующий элемент таблицы по индексу;
  • pairs – позволяет выполнять итерации по парам ключ-значение (key-value) таблицы;
  • pcall – защищенный вызов с заданными аргументами (позволяет обработать исключения);
  • print – простой вывод в stdout;
  • select – если первый аргумент функции имеет числовое значение, возвращаются все аргументы, следующие за аргументом с этим номером. Если первый аргумент — строка ’#’, возвращается общее число полученных аргументов;
  • string – модуль для работы со строками;
  • table – модуль для работы с таблицами. Расширен двумя собственными функциями (см. подробнее);
  • tonumber – преобразование в число;
  • tostring – преобразование в строку;
  • type – возвращает тип переданного аргумента в виде строки;
  • unpack – возвращает элементы таблицы;
  • xpcall – подобна pcall, но устанавливает новый обработчик ошибок;
  • error – вызов исключения.

Модули Tarantool:

  • ipairs – подобно pairs, но использует числовые ключи;
  • fun – модуль Luafun для Tarantool;
  • uuid – модуль работы с UUID (Universally unique identifier);
  • digest – модуль кодирования и хэширования;
  • utf8 – модуль для работы с UTF-8 строками;
  • decimal – модуль для точных вычислений с числами.

А также отдельные функции из модулей Tarantool:

  • 2 функции из Модуля JSON:
    • json.encode – конвертация Lua объекта в JSON строку;
    • json.decode – конвертация JSON строки в Lua объект.
  • 1 функция из YAML Модуля:
    • yaml.encode – конвертация Lua объекта в YAML строку.
  • 1 функция из модуля fiber:
    • fiber.sleep – ожидание с передачей управления планировщику.
  • 1 функция из модуля box:
    • box.NULL – нулевой указатель (NULL pointer).
  • 3 функции из модуля metrics:
    • metrics.counter – монотонно возрастающий счетчик;
    • metrics.gauge – метрика для числовых значений;
    • metrics.histogram – метрика для оценки интенсивности потока во времени.

Также доступны нестандартные функции собственной разработки, описание которых приведено далее.

1.2.2. Функции доступа к данным

Основные функции для доступа к данным в TDG входят в программный интерфейс репозитория. Кроме них, также доступны:

  • model_accessor.find(type_name, filter, options, context) – функция, возвращающая объекты, соответствующие заданным условиям. По умолчанию возвращаются первые 10 результатов. Пагинация осуществляется аналогично операциям программного интерфейса репозитория. Не рекомендуется к использованию – используйте более высокоуровневую функцию find из программного интерфейса репозитория.
  • shared_storage.new(namespace) – создаёт новое общее хранилище.
  • connector.send(output_name, obj, output_options) – направляет объект в секцию output для отправки в смежную систему.
  • 2 функции ODBC:
    • odbc.execute(connection_name, statement, params) – выполнение запроса через ODBC;
    • odbc.prepare(connection_name, query) – подготовка запроса через ODBC. Возвращает объект подготовленного запроса. См. Подробнее.

1.2.3. Функции управления обработкой

  • commands – позволяет выполнить произвольные команды, в том числе модифицируя объект или порядок его обработки. Для этого достаточно вернуть из клиентского кода не объект, а соответствующую команду или команды (в случае, если команд несколько, то необходимо вернуть таблицу, содержащую все команды). Всего возможны 4 варианта команд:

    • commands.make_delete(routing_key, filter, options) – удаляет объекты, соответствующие условиям фильтра. См. Синтаксис поля filter.
    • commands.make_update(routing_key, filter, updaters, options) – обновляет данные объектов, соответствующих условиям. См. синтаксис поля updaters в разделе про Запрос на обновление данных.
    • commands.make_insert(obj) – указанный объект возвращается в конвейер обработки данных (pipeline). Передав несколько команд, можно вернуть несколько объектов;
    • commands.make_ignore(obj) – прекращает обработку объекта.
  • request_context.get – возвращает контекст запроса.

  • this_storage.snapshot – аналог box.snapshot.

  • get_function – возвращает ссылку на функцию по её имени, если она доступна в песочнице.

  • spawn(pipeline, func_name, args, options) – запускает один или несколько файберов для выполнения функции func_name. Количество запускаемых файберов определяется количеством args.

  • spawn_n(pipeline, func_name, func_num, options) – запускает func_num количество файберов для выполнения функции func_name без аргументов.

1.2.4. Функции преобразования данных

  • lom.get_by_path (lom, path) – функция возвращает объект из Lua таблицы в нотации Lua Object Model. Выполняется разделение path на отдельные части с разделителем в виде точки. Затем в переданном lom выполняется поиск объекта с полем tag, равным первой части path. Далее операция поиска повторяется для каждой части path в результатах поиска предыдущего этапа.

    • lom – таблица в нотации Lua Object Model.
    • path – путь до объекта внутри lom с разделителем в виде точки ..
  • 3 функции для работы со значениями внутри объектов:

    • mapping_tools.get_by_path(obj, path, delimeter) – получение значения из объекта по пути;
    • mapping_tools.set_by_path(obj, path, value, delimeter) – задание значения в объекте по пути;
    • mapping_tools.just_get_and_set(source_object, source_path, target_object, target_path) – получить значение из одного объекта и записать в другой.
  • 2 функции, расширяющие модуль table :

    • table.cmpdeeply(got, expected) – глубокое сравнение двух таблиц. Возвращает результат сравнения, истину (true) или ложь (false).
    • table.append_table(where, from) – добавление одной таблицы к другой. При этом используется неглубокое (shallow) копирование.

1.2.5. Функции логирования

  • Функции записи сообщений в журнал (по аналогии с модулем log):
    • log.error('Error text');
    • log.warn('Warning text');
    • log.info('Information text');
    • log.verbose('Verbose level text');
    • log.debug('Debug level text').
  • Функция трассировки:

    • tracing.start_span – начинает span (основной блок трассировки в распределенных системах) и возвращает специальный объект. Для завершения трассировки выполнения функции используется метод finish возвращаемого объекта. Также у этого объекта имеется метод set_error, регистрирующий ошибку. См. Подробнее.

1.2.6. Функции работы с датами и временем

  • datetime – функции для работы со временем:
    • now – возвращает текущее время по Гринвичу (GMT) в наносеундах;
    • sec_to_iso_8601_date – преобразует число секунд в строку формата yyyy-MM-dd;
    • nsec_to_iso_8601_datetime – преобразует число наносекунд в строку формата yyyy-MM-ddTHH:mm:ss.SSSZ;
    • nsec_to_iso_8601_date – преобразует число наносекунд в строку формата yyyy-MM-dd;
    • iso_8601_datetime_to_nsec – преобразует строку даты и времени в число наносекунд;
      • Здесь строка даты и времени принимается в одном из следующих форматов:
        • yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ
        • yyyy-MM-dd'T'HH:mm:ssZZZZZ
        • yyyy-MM-dd'T'HH:mm:ss.SSS
        • yyyy-MM-dd'T'HH:mm:ss
        • yyyy-MM-dd'T'HH-mm-ss
        • yyyy-MM-dd'T'HHmmss.SZZZZZ
        • yyyy-MM-dd'T'HHmmssZZZZZ
        • yyyy-MM-dd'T'HHmmss.SSS
        • yyyy-MM-dd'T'HHmmss
    • iso_8601_date_to_nsec – преобразует строку даты формата yyyy-MM-dd в число наносекунд;
    • to_sec – преобразует наносекунды в секунды и преобразует к типу number;
    • to_millisec – преобразует наносекунды в милисекунды и преобразует к типу number;
    • seconds_since_midnight – возвращает количество секунд с начала суток по Гринвичу (GMT).
    • Набор констант, используемых для работы со временем:
      • NSEC_IN_SEC – число наносекунд в секунде;
      • NSEC_IN_MILLISEC – число наносекунд в милисекунде;
      • NSEC_IN_DAY – число наносекунд в сутках.
  • timezone – функции для работы с часовыми поясами:
    • now(timezone_id) – возвращает текущее местное время в наносекундах для указанного часового пояса;
    • seconds_since_midnight(timezone_id) – возвращает число секунд с начала текущих суток для указанного часового пояса;
    • curr_date_nsec(timezone_id) – возвращает время (дату) начала текущих местных суток в указанном часовом поясе в наносекундах.

1.2.7. Функции работы с последовательностями

  • sequence – генератор уникальных упорядоченных целых чисел. Уникальность чисел гарантируется в пределах отдельной последовательности с заданным именем, даже при вызове из разных файберов или на разных экземплярах. Для обеспечения уникальности при вызовах из разных экземпляров используется роль sequence_generator, которая выделяет доступные диапазоны чисел. При первом обращении или при исчерпании выданного ранее диапазона происходит выделение нового незанятого ранее диапазона уникальных чисел.
    • get(sequence_name) – возвращает ссылку на объект последовательности (если последовательность с таким именем отсутствует, то создаёт новую). У объекта есть единственный метод – next:
      • next – возвращает следующий элемент последовательности.

Примечание

По умолчанию файберам или экземплярам выделяются диапазоны по 10 номеров. Пример использования: если на двух разных экземплярах вызвать 1 раз пайплайн, который заполняет поле объекта уникальным номером с помощью метода next, то номера у объектов будут 1 и 11 соответственно. Если вызвать еще по 9 раз пайплайны, то номера объектов будут 2-10 и 12-20 на соответствующих экземплярах. Дальше, если запустить пайплайн еще раз на первом экземпляре, то будет получен номер 21. Если мы продолжим вызывать пайплайн на одном из экземпляров, то номера будут идти по порядку (22, 23, …).

1.2.8. Подключение новых функций

Важно

Подключать новые функции к безопасной среде исполнения категорически запрещено для сертифицированной версии TDG. Перед подключением новых функций в обычной версии TDG рекомендуется самостоятельно проверять их на уязвимости.

Для подключения к безопасной среде исполнения (песочнице) новых функций необходимо выполнить следующие действия:

  • создать модуль с подключаемыми функциями;
  • разместить файл модуля в файловой структуре всех инстансов;
  • инициировать применение конфигурации на всех инстансах.

1.2.8.1. Создание модуля с подключаемыми функциями

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

local exported_function = nil

local check_custom_function = os.getenv('CUSTOM_FUNCTION')
if check_custom_function ~= nil and check_custom_function ~= "" then
    local function custom_function()
        local magic_constant = 42
        return magic_constant
    end
    exported_function = custom_function
end

return {
    name = 'new_awesome_function',
    exports = exported_function
}

В примере продемонстрированы следующие возможности:

  • реализации произвольной логики проверок перед подключением новой функции;
  • задания логики функции непосредственно в файле модуля;
  • задания произвольного имени для вызова функции внутри песочницы (new_awesome_function).

Из файла должен возвращаться результат в виде имени и кода новой функции.

Имя новой подключаемой к безопасной среде исполнения функции указывается в виде строки name.

Код новой функции приводится в поле exports в одном из следующих форматов:

  • Ссылка на функцию, описанную в этом же файле (как в примере выше).
  • Ссылка на подключенный при помощи директивы require() модуль Tarantool.

1.2.8.2. Размещение файла модуля в файловой структуре

Для того чтобы ваша новая функция была доступна в песочнице, необходимо разместить файл с модулем подключаемой функции в специальной директории (возможно, потребуется создать эту директорию, если она не существовала ранее).

Файл размещается по адресу ../extensions/sandbox, где .. – это директория, в которой размещена директория с файлами „project_name“, обозначенная на следующей схеме как tdg.

.
├── tdg
├── extensions
    └── sandbox
        └── custom_function.lua    <-- sandboxed module interface

1.2.8.3. Применение конфигурации

После создания файла модуля с новой функцией для безопасной среды исполнения и размещения данного файла в корректной директории, новая функция еще не будет доступна. Считывание файлов из данной директории выполняется на этапе применения конфигурации инстанса.

Поэтому, для добавления функции понадобится вызвать процесс применения конфигурации. Это можно сделать разными способами, например:

  • перезагрузкой инстансов;
  • применением новой конфигурации.

Примечание

При применении к кластеру TDG новой конфигурации она проходит валидацию.

Попытка применения той же самой конфигурации, что уже используется, закончится неудачей.

При этом, если конфигурация является валидной (корректной), то в ответ на запрос не будет выведено ошибок. Сообщение о том, что конфигурация совпадает с имеющейся и не будет применена, будет доступно только в системном журнале (на вкладке logger данное сообщение будет отсутствовать).