Работа со скриптами приложений Qlik Sense с использованием Python и REST API
На связи Николаев Николай и Грищенко Константин.
В своей работе мы активно используем BI инструмент Qlik Sense (QS), в частности занимаемся мониторингом его серверов. А это значит, что за раз часто приходится анализировать состояние множества приложений (сейчас их более 1600 штук). В таких случаях спасает использование API (Application Programming Interface) QS (об этом подробнее в этом посте) и работа с БД QS напрямую. Однако БД не содержит детальную информацию, только общую по приложениям. Например, данных по скриптам загрузки (об этом пойдёт речь дальше) в ней нет. Поэтому, чтобы с ними работать, необходимо использовать REST API.
Что такое REST API? API – это набор инструментов, который позволяет одним программам взаимодействовать с другими. Representational State Transfer (REST) – архитектурный стиль взаимодействия компонентов распределённого приложения в сети, позволяющий получать и модифицировать данные и состояния удаленных приложений при помощи передачи HTTP-запросов.
В этом посте хотим рассказать об одном из вариантов использования API QS, возможно не совсем стандартном, для следующей ситуации.
QS для разграничения доступа к приложению предоставляет функционал Section Access. Section Access – это часть скрипта загрузки данных, в которую добавляется таблица безопасности, определяющая какую информацию может просматривать указанный пользователь. Qlik Sense использует эту таблицу для скрытия некоторых данных в приложении от пользователя на основе указанных прав. Выглядит этот раздел примерно так:
В предложении упомянута БД QS, дальше про нее речи больше не идет. У читателей может возникнуть вопрос, а зачем они используют API? Почему из БД информацию не получить.
Поэтому предлагаю пояснить, что в БД QS содержится не вся информация, и поэтому в тех случаях когда ее там нет, то используется API
Видно, что таблица доступов статична и создаётся разработчиком/владельцем приложения. Вот с этого и начинается проблема: сама эта таблица при изменении структуры систем безопасности/доменной структуры не поменяется. Следовательно, вообще все пользователи могут потерять доступ к приложениям, в которых был раздел Section Access. А такие изменения как раз и планировались в нашей организации.
Поэтому стояла задача поменять этот раздел во всех своих приложениях и предупредить владельцев приложений с таким разделом о необходимости корректировки. Понятно, что заходить в каждое приложение и глазами просматривать скрипт — не вариант. И готового метода в API, для того, чтобы это можно было сделать, нет. Как мы воспользовались API QS для работы со скриптами загрузки приложений QS расскажем дальше.
Как известно, у QS есть несколько видов API. Мы будем использовать два: для получения списка приложений и для работы с объектами приложений. Тот вид API, который мы использовали для манипуляций с объектами, работает по технологии websocket.
Итак, первым шагом на пути решения задачи будет подключение к серверу и аутентификация.
Аутентифицироваться на сервере QS можно двумя способами:
· по SSL сертификатам;
· при помощи NTLM.
Аутентификация NTLM отличается от сертификатов тем, что для подключения по этому протоколу необходимы только логин и пароль доменной учетной записи. Но так как логин и пароль передаются в коде в открытом виде, аутентификация при помощи NTLM может подойти не во всех случаях (например, если это не удовлетворяет требованиям кибербезопасности, принятым в организации).
Подключаться к серверу QS будем первым способом (по SSL сертификатам) — подробно о нём и о том, как экспортировать сертификаты можнопочитать в упомянутой выше статье. При подключении выполним шаги аналогичные описанным в том же посте, но с некоторыми отличиями: мы обойдемся без использования библиотеки qsAPI – вместо этого, получим ответ от сервера QS через requests.get() и сразу загрузим список приложений с их id в датафрейм pandas.
Для выполнения задачи понадобятся следующие библиотеки:
На всякий случай, пользовались мы такими версиями:
Python 3.9.7
requests == 2.26.0
pandas == 1.3.4
websocket_client == 1.6.4
И следует обратить внимание, что библиотека websocket и библиотека websocket_client —разные, и нам нужна именно websocket_client. При этом первую в нашем случае категорически рекомендуется не ставить, а если она уже есть – удалить.
Теперь создадим ключ xrfkey (необходимо, чтобы и в headers, и в url-адресе запроса к API он был один и тот же):
И зададим параметры для подключения к серверу: хост, имя домена в сети (userDirectory), учетная запись (УЗ) пользователя:
Также, при аутентификации на сервере QS потребуется задать заголовок http-запроса (в формате словаря):
Поясним немного о том, что описано выше. Заголовок включает в себя реквизиты УЗ пользователя QS (домен/УЗ), указание на формат получаемых данных (JSON), а также ключ пользовательской сессии Qlik (xrfkey).
Чтобы подключить сертификаты, нам необходимо указать путь к ним.
Примечание: Файл для сертификата clientandkey.pem состоит из содержимого файла client_key.pem и через строку – из содержимого файла client.pem.
Далее собираем url для подключения. Для целевого Endpoint указываем ранее сгенерированный xrfkeyи передаем url в запрос requests:
Примечание: каждый из API имеет свой набор конечных точек и портов, здесь показан запрос для получения списка всех приложений из QRS.
На этом настройки авторизации закончены. Посмотрим, что вернёт запрос на сервер:
В ответе список приложений в JSON
Для каждого приложения свой отдельный словарь с его параметрами: его id, дата создания, дата изменения, id владельца и т.д.
Первый этап пройден. Список приложений загружаем в датафрейм pandas для дальнейшей обработки:
Теперь подключаемся к движку QIX Engine при помощи технологии websocket (по сертификатам). Для этого потребуется весь набор сертификатов, ранее выгруженных в QMC. Указываем место, где они сохранены и их список:
URL для подключения к Qlik Engine собирается с указанием другого порта (4747 для QIX, в отличие от 4242 для подключения к репозиторию QRS):
На следующем шаге мы как раз и будем искать приложения, в скрипте загрузки которых есть раздел Section Access.
Чтобы получить скрипты по всем приложениям, нужно пройти циклом по списку id приложений (который ранее был получен через requests) и для каждого из них получить его загрузочный скрипт. Откроем тело цикла и начнем с выделения из датафрейма приложений с нужным id:
Разберём порядок работы с запросами. Сначала отправляем запрос на открытие приложения.
После открытия объекта приложения, можно отправлять на сервер JSON-запросы с любыми методами API QS, которые можно применить к данному объекту.
Сейчас нам нужно получить загрузочный скрипт приложения, поэтому мы формируем JSON с указанием метода GetScript:
Для создания подключения будем использовать метод create_connection. Указываем собранный url, способ аутентификации (по сертификатам), заголовок запроса:
Сформировав JSON-запрос, отправляем его и получаем ответ, который содержит id открытого приложения:
В ответе для запроса json_get_script_send, также в формате JSON, возвращается текст загрузочного скрипта приложения с идентификатором app_id:
После этого соединение websocket можно закрыть и сохранить полученный ответ в переменную:
И закрыть цикл, обработав исключения и записав полученные тексты загрузочных скриптов в датафрейм
В общем весь цикл получится такой:
И обработка ошибок:
Работа выполняется под учетной записи sa_sheduler, так как её обычно добавляют в таблицу section access, чтобы выполнялись автоматически tasks. У приложений же без section access для этой УЗ доступ есть. Поэтому, в случае ошибок доступа по каким-либо приложениям, мы точно будем знать, что в их скрипте загрузки есть раздел section access. Поэтому такие предложения нужно будет опросить под той УЗ, у которой есть доступ к ним (например, под УЗ владельца приложения). Либо элементарно записать всех таких владельцев приложений и сделать почтовую рассылку.
Получив датафрейм со списком всех приложений на сервере и текстами их загрузочных скриптов, отфильтруем его – оставим только те записи, по которым в тексте скрипта (поле qScript в примере) присутствует текст ‘Section Access;’:
Каждый элемент отфильтрованного датафрейма содержит в себе id, скрипт и гиперссылку приложения с section access. Например:
Чтобы получить более общую информацию о каждом приложении, мы можем добавить дополнительную информацию о приложениях и их владельцах:
У каждого из 189 доступных приложений, помимо их id, скриптов и гиперссылок, теперь есть дополнительная информация:
Датафрейм script_df объединяем с полученным ранее списком приложений (app_df), удаляя ненужные поля:
Оставим гиперссылку только для опубликованных приложений :
У опубликованных приложений гиперссылка останется:
У неопубликованных сотрется:
В результате полученные данные (включая детальную информацию по приложению и его владельцу) можно сохранить в CSV или Excel формате:
Изменение скрипта приложения
После получения скриптов можем сделать любое преобразование их текстов, например, при помощи string.replace() и загрузить их обратно в Qlik Sense аналогично тому, как мы выгрузили их до этого.
Для загрузки скрипта непосредственно в приложение в JSON-запросе вместо метода GetScript
нужно проставить метод SetScript и отправить следующий запрос:
Отправив соответствующий запрос на сервер, мы можем изменить раздел section access, например, добавить новых пользователей.
Раздел section access до:
Раздел section access после:
Итак, подведем итоги. Использование API QS помогает найти приложения с определённым составом скрипта, изменить этот скрипт, выполнить однообразную рутинную работу со множеством приложений довольно быстро. Данный подход может быть применим и к другим задачам с небольшими изменениями в коде. К минусам этого способа можно отнести тот факт, что оно эффективно только при массовых однотипных запросах. Если же необходим уникальный подход к каждому приложению, то способ скорее всего будет неуместным. С помощью API Qlik Sense вы сможете упростить работу с приложениями, оптимизировав типовые операции.