Всем привет! Меня зовут Макарий, я DevOps-инженер в команде кросс-платформенной инфраструктуры корпоративного супераппа VK Teams. Сегодня я продолжу рассказ о том, как мы применяем практики ChatOps в наших рабочих процессах. Первую часть о самих практиках и мини-аппах для их реализации можно прочитать здесь.

Напомню, ChatOps — модель организации работы и коммуникации внутри команды через общение, то есть через мессенджер. Такой подход объединяет разработчиков, DevOps-инженеров, QA-специалистов, инженеров поддержки, продуктовых менеджеров, аналитиков и других участников процесса в единую коммуникационную платформу. Мы рассмотрим открытый кросс-платформенный фреймворк OpsDroid, его возможности, напишем коннектор между OpsDroid и VK Teams, а также реализуем бота. Уверен, этот опыт откроет для ваc новые возможности, которые предоставляет ChatOps.

ChatOps и корпоративные мессенджеры


В предыдущей части мы рассмотрели основные принципы построения ChatOps:



Также мы поговорили о том, как работает автоматизация процессов с использованием корпоративного мессенджера:



Здесь нам на помощь приходит VK Teams — корпоративный суперапп от VK, который объединяет в себе мессенджер для общения с коллегами, ботов для автоматизации, свой таск-трекер, видеоконференции на 100 пользователей и платформу мини-приложений. 

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

Open-Source-фреймворк OpsDroid


OpsDroid — это кросс-платформенный фреймворк для разработки ChatOps-решений. Его основная идея заключается в создании единого центра управления ботом, который может работать одновременно на нескольких платформах, таких как Slack, MS Teams, Webex Teams, Facebook Messenger, Telegram, Matrix, Discord и других. Это позволяет командам использовать существующую инфраструктуру мессенджеров для управления операциями и взаимодействия с OpsDroid.

Взаимодействие между OpsDroid и платформой мессенджера осуществляется через коннекторы. Они представляют собой абстракцию над API и протоколами, используемыми различными мессенджерами и сервисами уведомлений. Коннекторы обеспечивают унифицированный интерфейс для взаимодействия с платформами и позволяют:

  • принимать и отправлять сообщения,
  • управлять каналами и пользователями,
  • получать уведомления о событиях и реагировать.

Например, для связи OpsDroid и VK Teams потребуется соответствующий коннектор, который свяжет Bot API VK Teams с функциональностью OpsDroid.



OpsDroid также предоставляет удобный интерфейс для создания ботов: в виде навыков (skills) — то есть модулей, которые обрабатывают входящие события (events), анализируют их, взаимодействуют с внешними сервисами, возвращают результат для обработки.

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

Linux, MacOS — используйте Docker (руководство). Вы также можете установить OpsDroid без использования Docker, просто с помощью:

pip3 install opsdroid[common]


Руководство для Windows.

Коннектор OpsDroid-VK Teams


Для связи VK Teams и OpsDroid можно написать простой коннектор.
Вот его код
import aiohttp
import asyncio

from opsdroid.connector import Connector
from opsdroid.events import Message


class ConnectorVKTeams(Connector):
"""A connector for VK Teams"""
	
    def __init__(self, config, opsdroid=None):
        # Инициализация коннектора
      
        super().__init__(config, opsdroid=opsdroid)
        self.name = "vkteams"

        self.opsdroid = opsdroid
        self.latest_update = None
        self.listening = True
        self.default_target = self.default_user
        self.session = None
        self._closing = asyncio.Event()
        self.loop = asyncio.get_event_loop()


        self.base_url = config.get("base-url", None)
        self.default_user = config.get("default-user", None)
        self.whitelisted_users = config.get("whitelisted-users", None)
        self.update_interval = config.get("update-interval", 1)
        # без токена бот работать не сможет
        self.token = config["token"]

    async def _get_messages(self):
        # Получение сообщений из ивентов. Ивенты получаем: events/get из Bot API

        data = {
            'token': self.token,
            'pollTime': 30,
            'lastEventId': 1
        }
        if self.latest_update is not None:
            data["lastEventId"] = self.latest_update

        await asyncio.sleep(self.update_interval)
        resp = await self.session.get(self.build_url("events/get"), params=data)

        if 200 == resp.status:
            json = await resp.json()
            await self._parse_message(json)

    async def _parse_message(self, response):
        # Отдаем сообщения, которые нашли в json-е ивента

        for event in response["events"]:
            user = self.get_user(event)
            target = self.get_target(event)
            parsed_event = await self.handle_messages(
                user=user,
                target=target,
                event_id=event.get("eventId"),
                raw_event=event
            )
            if parsed_event:
                if self.handle_user_permission(event, user):
                    await self.opsdroid.parse(parsed_event)
                else:
                    block_message = Message(
                        text="У вас нет доступа к взаимодействию с ботом",
                        user=user,
                        user_id=user,
                        target=target,
                        connector=self
                    )
                    await self.send(block_message)
                self.latest_update = event["eventId"]
            elif "eventId" in event:
                # игнорируем
                self.latest_update = event["eventId"]
    

Также в коннекторе необходимо реализовать методы для отправки сообщений, согласуя с Bot API.
Вот код реализации
import aiohttp

from opsdroid.connector import register_event
from opsdroid.events import Message, File

...


@register_event(Message)
async def send_message(self, message):

data = dict()
data["token"] = self.token
data["chatId"] = message.target
data["text"] = message.text

resp = await self.session.post(self.build_url("messages/sendText"), data=data)


@register_event(File)
async def send_file(self, file_event):

data = aiohttp.FormData()
data.add_field(
      	"token", str(self.token))
data.add_field(
        "chatId", str(file_event.target), content_type="multipart/form-data")
data.add_field(
        "file",
        await file_event.get_file_bytes(),
        content_type="multipart/form-data")

async with aiohttp.ClientSession() as session:
      	resp = await session.post(self.build_url("messages/sendFile"), data=data) 


Подробнее пример коннектора смотрите в репозитории. Коннектор позволяет OpsDroid понимать, когда приходит новое сообщение в VK Teams, и получать его содержимое, а также самому отправлять сообщения. Коннектор можно дополнительно расширить. Например, добавить поддержку всех возможных ивентов от OpsDroid:

from opsdroid.events import JoinGroup

...

if raw_event.get("type") == "newChatMembers":
    return JoinGroup(
        user=f"@[{user}]",
        user_id=user,
        event_id=event_id,
        target=target,
        connector=self,
        raw_event=raw_event,
    )


Или реализовать поддержку всех типов событий, которые доступны на платформе (для VK Teams см. /events/get).
Код реализации
from opsdroid.events import Message
from . import vkt_events

...

if raw_event['payload']['parts'][0].get("type") == "forward":
return vkt_events.Forward(
        user=f"@[{user}]",
        user_id=user,
        event_id=event_id,
        target=target,
        message=Message(
            text=raw_event['payload']['text'],
            user=f"@[{first_part['payload']['message']['from']['userId']}]",
            user_id=first_part['payload']['message']['from']['userId'],
            connector=self,
            raw_event=first_part,
        ),
        connector=self,
        raw_event=raw_event
)


Расширение коннектора увеличивает возможности навыков, которыми будут обладать ваши боты. В нашем случае добавим поддержку следующих ивентов: Reply, Forward, File, Voice, Sticker, Mention для нового сообщения, а также Edited Message, Deleted Message, Pinned/Unpinned Message, Join/Left chat для других событий в чате.

Еще OpsDroid предоставляет широкие возможности для тестирования. Принято полностью покрывать новый коннектор тестами.

Пример бота с OpsDroid


Давайте реализуем такого же бота, который отправляет на указанный имейл сообщение, если на него был дан ответ с ключевым словом «send_email». Мы будем использовать OpsDroid для создания кросс-платформенного бота, который будет работать как в VK Teams, так и в Slack и, например, в Matrix. Код не претерпит значительных изменений, мы обернем его в OpsDroid. Действия, которые мы ранее выполняли с распаковкой payload вложенного сообщения, перенесены в код коннектора, разобранный выше, в парсинг ивента типа Reply. В данном случае нам останется лишь получить содержимое ивента, которое привязано к основному:
message.linked_event.text


Навык, который будет использоваться в нашем кросс-платформенном боте в файле configuration.yaml, выглядит следующим образом:

from opsdroid.skill import Skill
from opsdroid.matchers import match_regex
from opsdroid.constraints import constrain_connectors


class SendEmailSkill(Skill):

    @match_regex(r'send_email', matching_condition="fullmatch")
    async def send_email(self, message):
        if not isinstance(message, Reply):
            await message.respond("Сделайте реплай на сообщение, "
                                  "которое хотите переслать на имейл")
            return

        message_for_email = f"{message.linked_event.user_id}:\n\n" \
                             f"{message.linked_event.text}\n\n"

        send_email(to=["your.real.email@mail.ru"],
                       subject=f"Сообщение из {message.connector.name}(opsdroid)",
                       text=message_for_email)
        await message.respond(f"Сообщение переслано на имейл")


    @match_regex(r'send_email', matching_condition="fullmatch")
    @constrain_connectors(['slack'])
    async def send_email_slack(self, message):
        slack = self.opsdroid.get_connector('slack')

        thread_timestamp = message.raw_event.get('thread_ts', None)
        replies = await slack.slack_web_client.conversations_replies(
            channel=message.target, ts=thread_timestamp
        )
        messages = replies['messages']

        thread_head = messages[0]
        users_info = await slack.slack_web_client.users_info(user=thread_head['user'])

        message_for_email += f"{users_info.get('user').get('real_name')}:" \
                             f"\n\n{thread_start['text']}\n\n"

        send_email(to=["your.real.email@mail.ru"],
                   subject=f"Сообщение из Slack (opsdroid)",
                   text=remove_emoji(message_for_email))
        await message.respond(f"Сообщение переслано на имейл")


Код этого навыка для Slack отличается, так как коннектор Slack не поддерживает тип ивента Reply. Здесь мы используем разбиение с помощью constrain_connectors, чтобы в случае, если бот принял ивент в Slack, он распарсил его одним способом, а если принял в VK Teams или в Matrix — то другим, более подходящим. Коды навыка для VK Teams и Matrix идентичны.

Подробнее пример навыка смотрите в репозитории. Для более глубокого погружения используйте полную документацию OpsDroid.

Затем нам необходимо организовать структуру проекта следующим образом:

.
├── Dockerfile*
├── configuration.yaml
└── skills
    └── email_sender (имя кастомного скилла)
        └── __init__.py

* Dockerfile — если вы запускаете OpsDroid с помощью docker.

Для этого выполним следующие команды:

cd /home/username/Projects

mkdir -p my_opsdroid_project/skills/email_sender

cd my_opsdroid_project

vim __init__.py  <- сюда положим код навыка

Соберем нашего кросс-платформенного бота:
configuration.yaml
logging:
  level: debug
  timestamp: true
 
welcome-message: false
 
# Web server
web:
  host: '0.0.0.0'
  port: 8080
 
## Parsers
parsers: []

## Connectors modules
connectors:
  vkteams:
    token: "VKT_BOT_TOKEN"  # <- токен, который получили у Метабота
    bot-name: "email_sender_bot"  # <- имя бота, которое задали Метаботу при создании
    base-url: "api.my-company.myteam.mail.ru/bot/v1/"  # <- base-url бот-апи
    repo: https://github.com/mboriskin/connector-vkteams  # <- код коннектора

  # как настроить slack - https://docs.opsdroid.dev/en/stable/connectors/slack.html
  slack:
    bot-token: "SLACK_BOT_TOKEN"
    bot-name: "email_sender_bot"
    socket-mode: true
    app-token: "SLACK_APP_TOKEN"

  # как настроить matrix - https://docs.opsdroid.dev/en/stable/connectors/matrix.html
  matrix:
    mxid: "@bot_account_username:matrix.org"
    password: "bot_account_password"
    rooms:
      'main': '#my-corporate-bots:matrix.org'
    nick: "Botty EmailSender"
   

## Skill modules
skills:
  ## Hello (https://github.com/opsdroid/skill-hello)
  hello: {}  # <- как пример, навык по умолчанию
 
  ## Отправить сообщение на имейл
  email_sender:
    path: /opt/opsdroid/skills/email_sender  # <- там лежит навык (если через docker)
    no-cache: true
    app-name: my_opsdroid_vkt


Соберем бота:
opsdroid config -f configuration.yaml build


Запустим в работу:
opsdroid start

Для запуска через Docker стяните скрипт startup.sh и Dockerfile из репозитория с примерами. Затем запустите скрипт для сборки бота:
IMAGE_NAME="my_opsdroid_vkt" ./startup.sh --build

Запустить скрипт можем как напрямую (для отладки и наблюдения за логами):
./startup.sh --run

Так и в фоне:
./startup.sh --runbg

И когда придет время, остановить бота:
./startup.sh --stop


Также можем удалить отработавший образ:
./startup.sh --remove


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

Например, в Slack:







В VK Teams:







И в Matrix:







OpsDroid представляет собой мощный кросс-платформенный фреймворк для разработки ChatOps-решений. Благодаря способности работать одновременно на нескольких платформах, таких как Slack, MS Teams, VK Teams и других, OpsDroid обеспечивает командам гибкость и удобство при управлении операциями и взаимодействии с ботами. Концепция коннекторов упрощает интеграцию с различными сервисами, обеспечивая единый интерфейс для взаимодействия. Навыки в OpsDroid позволяют разработчикам создавать функциональность ботов, обрабатывать события и взаимодействовать с внешними сервисами. Благодаря простой установке и настройке OpsDroid является эффективным инструментом для разработки кросс-платформенных ботов, способных оперативно выполнять задачи и обеспечивать эффективное взаимодействие с пользователями.

Готовые решения OpsDroid можно шарить между мессенджерами.


Можно найти множество уже готовых решений для OpsDroid и затем интегрировать их для использования в VK Teams или другом сервисе.
Список готовых решений
  • skill-ssh — навык для взаимодействия с Linux-серверами с помощью SSH-команд;
  • skill-devops — навык для взаимодействия с Docker и Gitlab;
  • skill-sysanalytics — мониторинг системы при запущенном экземпляре OpsDroid;
  • skill-nginx-rtmp — мониторинг запуска, остановки nginx-rtmp и состояния в целом;
  • skill-github-linker — предоставление ссылок на GitHub Issues и PR при упоминании;
  • skill-jenkins — навык для взаимодействия с Jenkins;
  • skill-repohook — предоставление ссылок на события в Git{Hub|Lab};
  • skill-docker-daemon — навык для управления Docker;
  • skill-k8s — навык для работы с Kubernetes; 
  • skill-shell — навык для запуска shell-скриптов;
  • skill-yourextip — получение своего внешнего IP-адреса в чате;
  • skill taginfo — навык для получения данных из OpenStreetMap;
  • skill-awx — навык для взаимодействия с AWX;
  • skill-grafana-annotation — навык для создания и просмотра аннотаций Grafana;
  • skill-prometheus-scrape — навык для сбора метрик через Prometheus прямо из чата;
  • skill-github — навык для взаимодействия с GitHub;
  • skill-cloudhealth — навык для взаимодействия с CloudHealth;
  • skill-reminders — для установки напоминаний;
  • skill-minecraft — навык для отслеживания и публикации логов сервера Minecraft;
  • skill-google-it — для ответа ссылкой на поиск в Google;
  • skill-iss — навык для определения местоположения МКС;
  • skill-formula1-schedule — обработка календаря «Формулы-1» и отправка напоминаний;
  • skill-random — навык для примера: отображение случайных событий;
  • skill-words — навык, использующий модуль NLTK для игры в слова;
  • skill-word-of-the-day — прислать слово дня из Оксфордского словаря английского языка.


Заключение


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

VK Teams как корпоративный суперапп предоставляет широкий набор инструментов для общения, автоматизации, управления задачами и видеоконференций. Успешная реализация ChatOps требует создания соответствующей культуры в команде, готовности использовать инструменты и принципы ChatOps.

OpsDroid является кросс-платформенным фреймворком для разработки ChatOps-решений. Он позволяет создать единую централизованную систему управления ботом, который может работать на различных платформах, таких как Slack, MS Teams, VK Teams, Matrix и других. Взаимодействие с мессенджерами осуществляется через коннекторы, которые предоставляют унифицированный интерфейс для обмена сообщениями, управления пользователями и получения уведомлений о событиях.

В качестве примера использования OpsDroid был рассмотрен простой бот, способный отправлять сообщения на указанный имейл при получении определенного ключевого слова. Благодаря гибкости OpsDroid и его возможности работать на различных платформах такой бот может быть использован как в VK Teams, так и в других мессенджерах, например Slack или Matrix.

Мы отметили возможность использования готовых решений OpsDroid, которые могут быть адаптированы и интегрированы для использования в VK Teams или других мессенджерах. Это позволяет разработчикам использовать уже существующие возможности и навыки для управления операциями и взаимодействия с ботами.

В целом благодаря OpsDroid и интеграции с VK Teams команды могут создавать эффективные и гибкие ChatOps-решения, улучшая коммуникацию, автоматизируя рутинные задачи.

Комментарии (0)