Создаем slack-бот на Python в Yandex.Cloud

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

Мы не любим отвлекаться от текущей работы, копаться в трекере задач и почте, чтобы найти нужный тикет или письмо от клиента. Нас беспокоят пропущенные напоминания и недоступные логи. Чат-боты и боты для поддержки процессов разработки популярны у разработчиков именно потому, что избавляют нас от нелюбимой рутины. Боты помогают нам в DevOps-трансформации.

Для разработки ботов удобно использовать serverless-технологии. Одно из преимуществ при работе с приложениями облачного бота, которые тоже размещены в облаке, — моментальный доступ к ним. В докладе на DevopsConf 2021 я подробно рассказал о концепции СhatOps и о том, какие из serverless-технологий стоит взять на вооружение уже сейчас. Кажется, что СhatOps и serverless созданы друг для друга.

Для меня ChatOps открыл прекрасный докладчик Джеймс Фрайман (James Fryman). Про преимущества такой организации инфраструктуры он рассказал в своем докладе еще в 2015 году. За последние годы актуальность ChatOps не только не пропала, но с каждым годом становится более востребованной. В России интерес стал заметен благодаря цифровой трансформации и новым игрокам на рынке IT.

ChatOps в России сегодня — это, в первую очередь, боты для Telegram и Slack (один из самых первых шагов, но не последний). Эти платформы лидируют по популярности среди платформ для ботов в России, а Slack входит в топ-3 корпоративных менеджеров в мировом рейтинге. 

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

Serverless-приложение — это совокупность сервисов и функций, размещенных в облаке. Чтобы скрыть особенности реализации можно воспользоваться сервисом API Gateway. С одной стороны, у нас появляется единая точка доступа к приложению, с другой открываются возможности модификации приложения не сказывающиеся на внешних потребителях. Это удобно при реализации slack-ботов. В нашем случае архитектура нашего приложения весьма примитивна: сервис API Gateway прикрывает несколько функций, одна из которых будет связана с Yandex Database.

Шаг 1. Регистрируем новое приложение в Slack

Начнем создание нашего бота с регистрации нового приложения в Slack. Переходим в панель Slack, при этом вы должны быть авторизованы и обладать соответствующими правами. Нажимаем кнопку Create a Slack App, заполняем начальную информацию о приложении. Позже её можно будет отредактировать. Задаем значение имени ServerlessBotApp и в выпадающем списке выбираем доступный workspace.

В разделе OAuth & Permissions переходим в пункт Scopes и выбираем права для нашего бота. Добавляем в Bot Token Scopes через кнопку Add an OAuth Scope значение chat:write. После того, как мы определили права для бота, можно переходить к установке приложения в workspace.

В разделе OAuth Tokens for Your Workspace нажимаем кнопку Install to Workspace, на открывшейся странице — кнопку Allow. В результате, в этой же секции мы получим Bot User OAuth Token. Токены любят тишину, постарайтесь не светить его, он пригодится чуть позже.

Мы создали в Slack точку доступа, к которой можно подключаться. Осталось создать точку доступа на стороне облака. Для разработки нашего приложения нам потребуется сервисный аккаунта в нашем облаке в Yandex.Cloud.

Шаг 2. Создаем сервисный аккаунт в Yandex.Cloud

Для оперирования ресурсами в облаке нам понадобится специальный сервисный аккаунт. Чтобы создать его, переходим в консоль облака. В текущем облаке выберем рабочий каталог и перейдем в пункт меню Сервисные аккаунты. Создадим новый сервисный аккаунт serverless-slack для работы приложения и выдадим ему роли в текущем каталоге. 

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

Шаг 3. Проверяем связь со Slack

Оставаясь в консоли облака переходим в дашборд текущего каталога и выбираем сервис API Gateway. Нажимаем кнопку Создать API-шлюз используем имя for-slack-bot. После публикации API-шлюза в спецификации появится секция servers со служебным доменом — при любых модификациях оставляем это поле без изменений. Этот адрес и будет точкой входа в приложение. В спецификации будут храниться все правила вызова наших serverless-функций.

Возвращаемся в панель Slack, чтобы связать наше приложение с облаком. В меню Basic Information нажимаем кнопку Add features and functionality и в открывшемся поле выбираем значение Event Subscribtions. Здесь нужно проверить, готова ли точка со стороны облака принимать запросы: на post-запрос от Slack мы должны выполнять параметры атрибута  Challenge, то есть отправлять ответ в виде:

HTTP 200 OK
Content-type: application/x-www-form-urlencoded
challenge=3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P

В облаке создаем функцию, которая будет отвечать на Challenge. в консоли облака переходим в дашборд текущего каталога и выбираем сервис Cloud Functions. Нажимаем кнопку Создать функцию и задаем ей имя for-slack-bot-challenge. Выбираем среду выполнения python3.7. Примечательно, что каждая функция может быть реализована на своем языке программирования.

В веб-редакторе создаем файл requirements.txt, подключаем в нем библиотеки:

Slack_sdk
Slack_bot
Boto3

Меняем содержимое файла index.py, созданного по умолчанию, в консоли на содержание того же файла в моем репозитории. Указываем точку входа index.handler. Увеличиваем тайм-аут до 5 секунд. Не забываем указываем сервисный аккаунт, созданный на предыдущем шаге. После того как функция будет создана у нее появится идентификатор.

Переходим в дашборд текущего каталога и выбираем сервис API Gateway. Выбираем for-slack-bot и редактируем его. Заменяем текущую спецификацию на содержимое из файла for-slack-bot.yml. При этом заменяем IDYOURFUNCTIONCHALLENGE на идентификатор созданной функции, а IDYOURACCOUNT — на идентификатор сервисного аккаунта, созданного ранее. Помним что секцию servers в спецификации ни в коем случае не меняем. После сохранения изменений в спецификации копируем значение url в секции servers

Переходим в панель Slack, выбираем наше приложение ServerlessBotApp. В секции Event Subscriptions указываем только что скопированный адрес в поле Request URL и дожидаемся появления Verified.

Шаг 4. Реализуем команду, интегрированную в Slack

Когда мы убедились что Slack видит наш API Gateway, настало время реализовать функциональность доступную в чате — команду. Для начала, в панели Slack получаем token и secret. В разделе OAuth & Permissions копируем Bot User OAuth Token и в дальнейшем используем в качестве значения переменной SLACK_BOT_TOKEN. А в разделе Basic Information в подразделе App Credentials копируем Signing Secret и в дальнейшем используем его в качестве значения переменной SLACK_SIGNING_SECRET.

Для любой функции, создаваемой далее обязательно задаем переменные SLACK_BOT_TOKEN и SLACK_SIGNING_SECRET помимо сервисного аккаунта.

В консоли облака переходим в дашборд текущего каталога и выбираем сервис Cloud Functions. Нажимаем кнопку Создать функцию. Задаем имя for-slack-bot-hello-from-serverless. Выбираем среду выполнения python3.7

В веб-редакторе создаем файл requirements.txt, подключаем в нем библиотеки:

Slack_sdk
Slack_bot
Boto3

Меняем содержимое файла index.py, созданного по умолчанию, в консоли на содержание того же файла в моем репозитории. Указываем точку входа index.handler. Увеличиваем тайм-аут до 5 секунд. Указываем идентификатор сервисного аккаунта и переменные SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET полученные ранее. Жмем кнопку — Создать версию и после копируем идентификатор нашей новой функции.

Функция готова и работает, опубликуем ее через сервис API Gateway. Выбираем for-slack-bot и редактируем его. Вставляем секцию /hello-from-serverless со всем ее содержимым из файла for-slack-bot.yml в спецификацию. Заменяем IDYOURFUNCTIONHELLO на идентификатор созданной функции, а  IDYOURACCOUNT — на идентификатор сервисного аккаунта. Сохраняем изменения.

Функция опубликована и требуется создать команду в нашем Slack-приложении. В панели Slack выбираем созданное приложение ServerlessBotApp. В секции Slash Commands нажимаем кнопку Create New Command

В поле Command вводим /hello-from-serverless. В поле Request URL указываем адрес API Gateway, дополнив его /hello-from-serverless. Можем, но не обязаны заполнить поле Short Description. Нажимаем Save. Следуя инструкции, переустанавливаем Slack-приложение. После этого в workspace появится возможность вызвать сконфигурированную команду.

Шаг 5. Реагируем на сообщение пользователя

Мы уже можем расширять функциональность Slack с помощью команд и реализовать выполнение функции внутри Yandex.Cloud. Но наш бот не совсем бот, он не умеет реагировать на сообщения пользователя. Исправим это.

Переходим в сервис Cloud Functions. Нажимаем кнопку Создать функцию. Задаем имя for-slack-bot-small-talk. Выбираем среду выполнения python3.7.

Создаем файл requirements.txt с содержимым аналогично предыдущему разу. Меняем содержимое файла index.py созданного по умолчанию, в консоли на содержание того же файла в моем репозитории. Указываем точку входа index.handler. Увеличиваем тайм-аут до 5 секунд.

Указываем сервисный аккаунт и переменные SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, полученные ранее. Нажимаем кнопку Создать версию, не забываем скопировать идентификатор.

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

В сервисе API Gateway находим шлюз for-slack-bot, отредактируем его содержание: заменим секцию / на аналогичную, содержащуюся в файле for-slack-bot.yml, только заменяем  IDYOURFUNCTIONSMALLTALK на идентификатор вашей функции. Сохраняем.

Переходим на панель управления Slack выбираем  созданное приложение ServerlessBotApp. В секции Event Subscriptions передвигаем ползунок Enable Events в положение on. Указываем адрес API Gateway в поле Request URL и дожидаемся появления Verified.

В секции Subscribe to bot events на той же странице нажимаем кнопку Add Bot User Event и выбираем message.im.

Как только все заработает, возникнет автоматическое взаимодействие. Поток сообщений будет отправляться в API Gateway. На нашей стороне мы уже можем реализовать полноценный диалог с подключением других необходимых ресурсов. Можем расширять функциональность через подписку на определенные типы событий. Сейчас мы подписались только на один тип — получение сообщений. 

Через точку доступа Slack отправляет запросы в виде POST-запросов, на стороне Yandex.Cloud вызывается функция. Запрос обрабатывается функцией и генерируется ответ.

Созданная ранее функция реагирует на сообщения пользователя ":wave:" и "knock knock". Теперь у нас уже есть практически полнофункциональный бот, но нам предстоит подключить к нашему serverless-приложению СУБД для хранения данных, для хранения состояния и другой информации.

Шаг 6. Создаем БД для хранения данных

Для работы нашего serverless-приложения будем использовать СУБД Yandex Database, более подробно о ее особенностях можно почитать тут.

В консоли облака переходим в дашборд текущего каталога и выбираем сервис Yandex Database. Нажимаем кнопку Создать базу данных. Создаем базу данных с именем for-slack-bot, выбираем serverless в качестве модели.

После создания БД переходим в ее содержимое, выбираем пункт Навигация и нажимаем кнопку SQL-запрос. В веб-редакторе в поле Запроса вставляем следующий текст:  

CREATE TABLE coffee
(
   id Utf8,
   name Utf8,
   PRIMARY KEY (id)
);

После успешного выполнения запроса в нашей БД появится таблица. В разделе Навигация выберете таблицу coffee и добавьте пару строк. Одну из строк с идентификатором равному 1.

Перейдите в раздел Обзор. В интерфейсе вы увидите секцию YDB эндпоинт, в ней содержатся данные для формирования необходимых переменных. Для работы функции с Yandex Database потребуется три переменные. Переменная ENDPOINT будет иметь вид grpcs://ydb.serverless.yandexcloud.net:1234, переменную DATABASE обязательно начинать с /ru-central1/..., а переменная USE_METADATA_CREDENTIALS в нашем случае выставляется равной 1.

Шаг 7. Реализуем команду, интегрированную в Slack и работающую с YDB

Оставаясь в рабочем каталоге выбираем сервис Cloud Functions и привычным образом создаем новую функцию с именем for-slack-bot-what-kind-of-coffee. Выбираем среду выполнения python3.7

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

ydb==0.0.41

Меняем содержимое файла index.py созданного по умолчанию, в консоли на содержание того же файла в моем репозитории. Указываем точку входа index.handler. Увеличиваем тайм-аут до 5 секунд.

Указываем сервисный аккаунт и переменные SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, полученные ранее. Добавляем еще три переменные для работы с YDB: ENDPOINT, DATABASE, USE_METADATA_CREDENTIALS. Нажимаем кнопку Создать версию, не забываем скопировать идентификатор.

Оставаясь в рабочем каталоге в облаке переходим в сервис API Gateway выбираем for-slack-bot и редактируем его. Вставляем секцию /what-kind-of-coffee со всем ее содержимым из файла for-slack-bot.yml.

Заменяем IDYOURFUNCTIONCOFFEE на идентификатор созданной функции, а IDYOURACCOUNT — на идентификатор вашего сервисного аккаунта, созданного ранее. Сохраняем изменения. В этот момент у нас появилась опубликованная функция, способная получить данные из Yandex Database, остается вызвать ее из Slack.

В панели управления Slack выбираем созданное приложение ServerlessBotApp. В секции Slash Commands нажимаем Create New Command. Кстати, название команды и запрос URL со стороны Slack всегда можно отредактировать^ что очень удобно.

В поле Command вводим /what-kind-of-coffee, в поле Request URL указываем адрес API Gateway, дополнив его /what-kind-of-coffee. Нажимаем Save. Следуя инструкции, переустанавливаем Slack-приложение. Теперь в workspace можно вызвать новую команду.

Мы получили бот, с которым можно работать, расширять его возможности и прокачивать функциональность. Теперь вы можете создавать полноценные диалоги и получать данные.

Полные исходные тексты всех файлов, инструкции и видео шагов для реализации бота есть в репозитории.

P.S. Пара нюансов реализации

Первый. Когда вы создаете бота для Slack, рекомендую обратить внимание на реакцию на ввод команды. Эта реакция должна быть меньше 3 секунд. Если вы не укладываетесь в это время, Slack считает это ошибкой и начинает посылать сообщения в чат пользователю о том, что команда недоступна.

Лучше не дожидаться выполнения команды, а записать в базу данных сам факт ее вызова. Затем уже отдельной функцией обработать очередь вызовов команд, а результат вызова команды дослать позже. К тому моменту, как пользователь обратится в чат, вы сможете ему ответить полноценным диалогом.

Второй. В Yandex.Cloud есть активно растущее serverless-коммьюнити Yandex Serverless Ecosystem в Telegram, где можно задавать вопросы, возникающие в процессе создания serverless-ботов и получать ответы от единомышленников и коллег.

И последнее: сейчас действует программа free tier. Вы можете разработать свое приложение, в том числе и slack-бот, при этом сервисы тарифицироваться не будут, если вы уложитесь в лимиты программы.

Источник: https://habr.com/ru/post/564684/


Интересные статьи

Интересные статьи

Аппарат линейной алгебры применяют в самых разных областях — в линейном программировании, эконометрике, в естественных науках. Отдельно отмечу, что этот раздел математики востребован ...
Привет, Хабр! Сегодня хочу поделиться своим небольшим домашним проектом:ModulationPy (GiHub)- модуль для моделирования цифровых модемов (это которые PSK и QAM). Проект б...
Подготовка к техническому собеседованию по Python — нелёгкая задача. На таком собеседовании вам, вполне возможно, встретятся задачи на вывод символов по заданным шаблонам. Если вы хотите ...
Недавно я публиковал статью о том, как быстро настраивать npm-пакеты перед публикацией в opensource. В ней я разобрал настройку версионирования, CI, построение воркфлоу и удобный деплой на страни...
Сегодня мы публикуем второй материал из цикла, посвящённого использованию Python в Instagram. В прошлый раз речь шла проверке типов серверного кода Instagram. Сервер представляет собой монолит, н...