Песочница для запуска python-скриптов в ORBISmap
Для реализации возможности запуска пользовательских скриптов в рамках ORBISmap - был разработан модуль ORBISmap py-sandbox
. Который позволяет в изолированной среде выполнять python-скрипты. Для удобства разработки скриптов была разработана библиотека omlibs
, упрощающая разработку скриптов.
Для корректной обработки скрипты должны:
- иметь в своем описании функцию
main()
без параметров. Запуск пользовательского скрипта в ORBISmap интерпретируется в вызов данной функции; - функция
main
должна возвращать0
в случае успешного завершения, любое другое число, если произошла ошибка; - для работы с БД использовать библиотеку
omslib.v1.pg
; - для работы с REST API использовать библиотеку
omslib.v1.OMSApi
; - для работы с переменными окружения использовать библиотеку
omslib.v1.Variables
; - для логирования процесса выполнения скрипта использовать библиотеку
omslib.v1.GLog
Пример структуры скрипта:
from omlibs.v1 import (
pg,
GLog,
OMSApi,
Checks,
Variables,
)
def func1(v1):
# выполнение пользовательских скриптов
pass
def func2(v1, v2):
# выполнение пользовательских скриптов
pass
def main():
"""Точка входа.
Выполнение скрипта интерпретируется в вызов данной функции
"""
try:
res1 = func1()
return func2(res1, 100500)
except Exception as e:
GLog.exception(e)
return -1
Обновление ORBISmap вручную
Основные шаги:
- Обновление
docker-compose.yml
- Обновление ORBISmap
- Обновление
orbismap.service
Обновление docker-compose.yml
Необходимо добавить новый сервис песочницы, а так же "внешний" memcached (в случае, если его еще нет):
py_sandbox:
image: "registry.orbismap.com/python-sandbox:1.0.5"
restart: always
user: untrusted
volumes:
- ${PWD}/extern/scripts:/oms_scripts:ro
env_file: orbismap.env
memcached:
image: "memcached:alpine"
restart: always
В сервис oms2
добавить точку монтирования /etc/cron.d
:
oms2:
image: "registry.orbismap.com/orbis/oms-mono:ВЕРСИЯ"
restart: always
volumes:
- ${PWD}/extern:/oms/extern
- ${PWD}/extern:/tilecache/extern
- orbismap-cron-d:/etc/cron.d
Добавить том orbismap-cron-d
:
volumes:
orbismap-pg-data:
orbismap-mg-data:
orbismap-mg-config:
orbismap-cron-d:
Обновление ORBISmap
Обновление проводится штатно до требуемой версии.
Обновление orbismap.service
После обновления ORBISmap необходимо обновить внешний сервис ORBISmap. Для этого:
- Остановим запущенный сервис -
sudo service orbismap stop
- Заменим бинарный файл сервиса на новый -
orbismap2/distrib/orbisap.service
(важно, чтобы у файла были права на запуск) - Запустим сервис -
sudo service orbismap start
Библиотека omlibs
Представляет собой пакет модулей Python. Основные компоненты:
pg
Библиотека, инкапсулирующая низкоуровневую работу с БД, и предоставляющая класс работы с БД. Данный класс представляет высокоуровневые функции работы с БД:
select
- Основная функция для осуществления выборок данных из БД. Основные параметры функции:
text: str
: Текст запроса с подстановками из argsargs: dict
: Список или словарь со значениями параметровmsg: str
: Особое сообщение об ошибке для пользователяddl: list
: Список ключей для экранирования параметровseq: bool
: Указывает, что в случае списка нужен генератор, целесообразно использовать в случае больших выборокone_row: bool
: Указывает, что нужна только первая строкаone_col: bool
: Указывает, что нужна только первая колонка
Пример использования:
from omlibs.v1 import (
pg,
Checks
)
def main():
# Предполагается, что значение фильтра по orbis_id, а также коды карты и слоя уже известны и получены
# Проверка полученных данных
map_code = "map"
layer_code = "azs"
oid_filter = 5
kwargs = {
'args': {
'map': Checks.check_str(map_code, "код карты"),
'layer': Checks.check_str(layer_code, "код слоя"),
'filter_limit': Checks.check_int(oid_filter, "фильтр по orbis_id"),
},
'seq': True,
'ddl': ['map', 'layer'],
'msg': 'Ошибка выборки данных из "%s"."%s"' % (map_code, layer_code)
}
res = pg().select('''
SELECT *
FROM %(*map)s.%(*layer)s
WHERE orbis_id < %(filter_limit)s;
''', **kwargs)
for i in res:
# Обработка данных выбранной строки
pass
return 0
execute
- Основная функция выполнения всех запросов, кроме select. Основные параметры функции:
text: str
: Текст запроса с подстановками из argsargs: dict
: Список или словарь со значениями параметровmsg: str
: Особое сообщение об ошибке для пользователяddl: list
: Список ключей для экранирования параметровwith_result: bool
: Флаг возвращения результата выполнения - исключает флагwith_affected
with_affected: bool
: Флаг возвращения количества затронутых строк
Пример использования:
from omlibs.v1 import (
pg,
Checks
)
def main():
# Предполагается, что значение фильтра по orbis_id, а также коды карты и слоя уже известны и получены
# Проверка полученных данных
map_code = "map"
layer_code = "azs"
oid = 5
kwargs = {
'args': {
'map': Checks.check_str(map_code, "код карты"),
'layer': Checks.check_str(layer_code, "код слоя"),
'orbis_id': Checks.check_int(oid, "orbis_id"),
'label': 'АЗС новая'
},
'ddl': ['map', 'layer'],
'msg': 'Ошибка изменения данных в "%s"."%s"' % (map_code, layer_code)
}
pg().execute('''
UPDATE %(*map)s.%(*layer)s
SET label = %(label)s
WHERE orbis_id = %(orbis_id)s;
''', **kwargs)
return 0
OMSAPI
Библиотека, инкапсулирующая работу с ORBISmap REST API, и предоставляющая класс работы с REST API OMSApi
. Данный класс представляет высокоуровневые функции работы с сущностями ORBISmap. В настоящий момент реализованы следующие функции:
get_token
- Получить токен авторизации пользователя для работы с ORBISmap REST API. Параметры функции:
login: str
: логин пользователя
Пример использования:
from omlibs.v1 import (
OMSApi,
GLog,
)
def main():
login = "user"
GLog.debug('Получение токена авторизации пользователя')
oms_api = OMSApi()
token = oms_api.get_token(login)
return 0
# Использование ORBISmap REST API с полученным токенм
get_layer
- Получить модель слоя. Параметры функции:
map_code: str
: код карты слояlayer_code: str
: код слоя
Пример использования:
from omlibs.v1 import (
OMSApi,
GLog,
)
def main():
map_code = "map"
layer_code = "azs"
GLog.debug('Выполнение REST API выборки данных')
oms_api = OMSApi()
layer = oms_api.get_layer(map_code, layer_code)
return 0
# Выполнение операций с полученной моделью слоя
get_layer_objects
- Получить список объектов слоя. Параметры функции:
map_code: str
: код карты слояlayer_code: str
: код слояfields_codes: str
: список кодов колонок объектов
Пример использования:
from omlibs.v1 import (
OMSApi,
GLog,
)
def main():
map_code = "map"
layer_code = "azs"
fields_codes = "name,description"
GLog.debug('Выполнение REST API выборки данных')
oms_api = OMSApi()
objects = oms_api.get_layer_objects(map_code, layer_code, fields_codes)
return 0
# Выполнение операций с полученными объектами слоя
get_layer_object
- Получить информацию по объекту слоя. Параметры функции:
map_code: str
: код карты слояlayer_code: str
: код слояobject_id: int
: ID объекта
Пример использования:
from omlibs.v1 import (
OMSApi,
GLog,
)
def main():
map_code = "map"
layer_code = "azs"
object_id = 1
GLog.debug('Выполнение REST API выборки данных')
oms_api = OMSApi()
object_data = oms_api.get_layer_object(map_code, layer_code, object_id)
return 0
# Выполнение операций с полученным объектом слоя
edit_layer_object
- Изменить объект слоя. Параметры функции:
map_code: str
: код карты слояlayer_code: str
: код слояobject_id: int
: ID объектаobject_data: dict
: данные объекта
Пример использования:
from omlibs.v1 import (
OMSApi,
GLog,
)
def main():
map_code = "map"
layer_code = "azs"
object_id = 1
GLog.debug('Выполнение REST API выборки данных')
oms_api = OMSApi()
object_data = oms_api.get_layer_object(map_code, layer_code, object_id)
# Выполнение операций с полученным объектом слоя
object_data["fields"]["name"] += " (new)"
GLog.debug('Выполнение REST API сохранения данных')
oms_api.edit_layer_object(map_code, layer_code, object_data["id"], object_data)
return 0
import_layer
- Выполнить импорт данных в слой. Параметры функции:
map_code: str
: код карты слояlayer_code: str
: код слояfile_path: str
: путь до файла с данными для импортаaction: str
: действие при импорте (замена/объединение) [OMSApi.IMP_ACT_OVERWRITE
,OMSApi.IMP_ACT_MERGE
]
В настоящий момент поддерживается импорт в слой, через передачу файл в теле POST-запроса, таким образом есть ограничение на размер файла для импорта.
Пример использования:
import requests
from omlibs.v1 import (
OMSApi,
GLog,
)
def main():
map_code = "map"
layer_code = "azs"
GLog.debug('Скачивание файлов со сторонних ресурсов')
url = 'https://oms-tests.orbismap.com/static/media/_py_scripts_test/azs.csv'
r = requests.get(url)
# важно: сохранять файлы можно только в темповую директорию
file_path = "/tmp/azs123.csv"
with open(file_path, "wb") as code:
code.write(r.content)
GLog.debug('Выполнение REST API изменения данных (импорт)')
oms_api = OMSApi()
res = oms_api.import_layer(map_code, layer_code, file_path)
GLog.debug(res)
return 0
Variables
Библиотека, инкапсулирующая работу с переменными окружения работы скриптов ORBISmap, и предоставляющая класс работы с переменными Variables
. Данный класс представляет высокоуровневые функции работы с переменными окружения и предоставляем следующие функции:
get_var
- gолучить значение конкретной переменной по имени. Параметры функции
name: str
- имя переменной
vars
- cвойство-словарь переменных окружения скрипта
Пример использования:
from omlibs.v1 import (
Variables,
GLog,
)
variables = Variables()
def main():
# Получаем текущие значения переменных
cur_vars = variables.vars
for item in cur_vars.items():
# Проводится анализ имеющихся переменных
pass
# Модифицируем текущие значения переменных
cur_vars = dict()
cur_vars['str1'] = 'String Value 1'
cur_vars['int1'] = 100500
cur_vars['float1'] = 100.5
cur_vars['bool1'] = True
cur_vars['list1'] = ['str', 100500, 100.5, False]
cur_vars['dict1'] = {
'k1': 'v1',
'k2': 100,
'k3': 1.5,
'k4': True,
'k5': ['s', 1, 0.5, False],
'k6': {'kk1': 'vv1'},
}
# Сохраняем новые значения переменных
variables.vars = cur_vars
return 0
GLog
Библиотека, инкапсулирующая работу с логированием процесса выполнения скриптов в ORBISmap, и предоставляющая класс работы с логами GLog
. Данный класс представляет высокоуровневые функции работы с сущностями ORBISmap. В настоящий момент реализованы следующие функции:
info
- записывает информационное сообщение в лог работы скриптаdebug
- записывает отладочное сообщение в лог работы скриптаwarning
- записывает предупреждающее сообщение в лог работы скриптаerror
- записывает сообщение об ошибке в лог работы скриптаexception
- записывает сообщение об исключении. Более развёрнутая запись, по сравнению сerror
Пример использования:
from omlibs.v1 import (
GLog,
)
def main():
GLog.info('Информация')
GLog.debug('Отладка')
GLog.warning('Предупреждение')
GLog.error('Ошибка')
# Для логирования исключений лучше использовать GLog.exception
try:
1/0
return 0
except Exception as e:
GLog.exception(e)
return 1
Checks
Библиотека, инкапсулирующая базовые проверки переменных, и предоставляющая класс работы с проверками Checks
. Данный класс представляет следующие функции проверок:
check_str
- Функция проверок строк. Проверяет, что переданный параметр является валидной строкой, в случае несоответствия возбуждает исключение. Параметры функции:
data: object
: Данные, предположительно строкаarg: str
: Имя проверяемого параметраallow_empty: bool
: Флаг разрешения пустой строкиallow_none: bool
: Флаг допустимости None
check_int
- Функция проверок целых чисел. Проверяет, что переданный параметр является валидным целым числом, в случае несоответствия возбуждает исключение. Параметры функции:
data: object
: Данные, предположительно строкаarg: str
: Имя проверяемого параметраallow_negative: bool
: Флаг разрешения отрицательных значенийallow_none: bool
: Флаг допустимости None
check_float
- Функция проверок вещественных чисел. Проверяет, что переданный параметр является валидным вещественным числом, в случае несоответствия возбуждает исключение. Параметры функции:
data: object
: Данные, предположительно строкаarg: str
: Имя проверяемого параметраallow_negative: bool
: Флаг разрешения отрицательных значенийallow_none: bool
: Флаг допустимости None
check_bool
- Функция проверки булевых переменных. Осуществляет приведение переданного параметра к булевому типу. Параметры функции:
data: object
: Данные, предположительно логический типarg: str
: Имя проверяемого параметраsmart: bool
: Флаг распознавания из строкиallow_none: bool
: Флаг допустимости None