1.2. Безопасная среда исполнения¶
Пользовательский код в TDG исполняется отдельно от собственного кода TDG — в безопасной изолированной среде, называемой песочницей (или sandbox). При этом используется JIT-компилятор LuaJIT.
Для доступа к данным, хранящимся в TDG, используйте функции программного интерфейса репозитория. Все остальные функции и возможности, которые можно использовать при написании пользовательского кода обработки в песочнице, описаны в данном разделе.
Все функции можно разделить на следующие категории:
Стандартные — подключаемые сторонние модули и функции:
Отдельные функции из Tarantool-модулей;
Нестандартные — собственные разработки:
Также имеется возможность подключить к безопасной среде исполнения новые произвольные функции. Как это сделать, описано в разделе Подключение новых функций.
Важно
Подключать новые функции к безопасной среде исполнения категорически запрещено для сертифицированной версии 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
— конвертация JSO-строки в 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
— позволяет выполнить произвольные команды, в том числе модифицируя объект или порядок его обработки. Для этого достаточно вернуть из клиентского кода не объект, а соответствующую команду или команды. В случае, если команд несколько, необходимо вернуть таблицу, содержащую все команды. Всего возможны четыре варианта команд:commands.make_delete(routing_key, filter, options)
— удаляет объекты, соответствующие условиям фильтра. См. Синтаксис поля filter;commands.make_update(routing_key, filter, updaters, options)
— обновляет данные объектов, соответствующих условиям. См. синтаксис поляupdaters
в разделе про Запрос на обновление данных;commands.make_insert(obj)
— указанный объект возвращается в конвейер обработки данных (pipeline). Передав несколько команд, можно вернуть несколько объектов;
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) копирование.
2 функции модуля
soap
, который позволяет преобразовывать SOAP-запрос в формате XML в объекты Lua и обратно:soap.decode(doc)
— получает на вход строку, содержащую XML-документ. Возвращает объекты Lua, полученные в результате парсинга XML:строка, содержащая указатель на пространство имен (
namespace
);строка с именем метода, переданного в SOAP-запросе (
method
);Lua-таблица, которая содержит значения, переданные в тэгах SOAP-запроса (
entries
);
soap.encode(data)
— получает на вход Lua-таблицу. Возвращает строку, содержащую XML-документ.
1.2.5. Функции логирования¶
Функции записи сообщений в журнал (по аналогии с модулем Tarantool
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
в число наносекунд;millisec_to_formatted_datetime
— преобразует милисекунды в заданную шаблоном строку даты и времени;custom_datetime_str_to_nsec
— преобразует заданную шаблоном строку даты или даты и времени в наносекунды;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
, где ..
— это
директория, в которой размещена директория с файлами TDG,
обозначенная на следующей схеме как tdg
.
.
├── tdg
├── extensions
└── sandbox
└── custom_function.lua <-- файл модуля с подключаемыми функциями
Альтернативно, файл модуля можно поместить в архив .zip
, посредством которого загружается конфигурация TDG.
В архиве файл модуля необходимо разместить по такому же пути — ../extensions/sandbox
.
1.2.8.3. Применение конфигурации¶
После создания файла модуля с новой функцией для безопасной среды исполнения и размещения данного файла в корректной директории, новая функция еще не будет доступна. Считывание файлов из данной директории выполняется на этапе применения конфигурации экземпляра.
Поэтому для добавления функции понадобится вызвать процесс применения конфигурации. Это можно сделать разными способами, например:
перезагрузкой экземпляров;
Примечание
При применении к кластеру TDG новой конфигурации она проходит валидацию.
Попытка применения той же самой конфигурации, что уже используется, закончится неудачей.
При этом, если конфигурация является валидной (корректной), то в ответ на запрос не будет выведено ошибок. Сообщение о том, что конфигурация совпадает с имеющейся и не будет применена, будет доступно только в системном журнале (на вкладке logger данное сообщение будет отсутствовать).