updates the implementation of the slack backend for notifications

Use the slack_sdk instead of the deprecated slackclient. Because according to the official documentation:
>  The slackclient PyPI project is in maintenance mode now and slack-sdk project is the successor.
With this commit one UPGRADE BLOCKER from requirements/requirements.in is removed. Als the license for slack_sdk
is updated and unit tests for slack notifications backend are added.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
This commit is contained in:
Daniel Ziegenberg
2021-10-21 18:25:40 +02:00
parent 69ae731898
commit e7064868b4
7 changed files with 88 additions and 24 deletions

View File

@@ -4856,7 +4856,7 @@ msgid "Exception connecting to PagerDuty: {}"
msgstr "" msgstr ""
#: awx/main/notifications/pagerduty_backend.py:87 #: awx/main/notifications/pagerduty_backend.py:87
#: awx/main/notifications/slack_backend.py:48 #: awx/main/notifications/slack_backend.py:49
#: awx/main/notifications/twilio_backend.py:47 #: awx/main/notifications/twilio_backend.py:47
msgid "Exception sending messages: {}" msgid "Exception sending messages: {}"
msgstr "" msgstr ""

View File

@@ -2,7 +2,8 @@
# All Rights Reserved. # All Rights Reserved.
import logging import logging
from slackclient import SlackClient from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
from django.utils.encoding import smart_text from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -28,7 +29,7 @@ class SlackBackend(AWXBaseEmailBackend, CustomNotificationBase):
self.color = hex_color self.color = hex_color
def send_messages(self, messages): def send_messages(self, messages):
connection = SlackClient(self.token) client = WebClient(self.token)
sent_messages = 0 sent_messages = 0
for m in messages: for m in messages:
try: try:
@@ -36,15 +37,15 @@ class SlackBackend(AWXBaseEmailBackend, CustomNotificationBase):
if r.startswith('#'): if r.startswith('#'):
r = r[1:] r = r[1:]
if self.color: if self.color:
ret = connection.api_call("chat.postMessage", channel=r, as_user=True, attachments=[{"color": self.color, "text": m.subject}]) response = client.chat_postMessage(channel=r, as_user=True, attachments=[{"color": self.color, "text": m.subject}])
else: else:
ret = connection.api_call("chat.postMessage", channel=r, as_user=True, text=m.subject) response = client.chat_postMessage(channel=r, as_user=True, text=m.subject)
logger.debug(ret) logger.debug(response)
if ret['ok']: if response['ok']:
sent_messages += 1 sent_messages += 1
else: else:
raise RuntimeError("Slack Notification unable to send {}: {} ({})".format(r, m.subject, ret['error'])) raise RuntimeError("Slack Notification unable to send {}: {} ({})".format(r, m.subject, response['error']))
except Exception as e: except SlackApiError as e:
logger.error(smart_text(_("Exception sending messages: {}").format(e))) logger.error(smart_text(_("Exception sending messages: {}").format(e)))
if not self.fail_silently: if not self.fail_silently:
raise raise

View File

@@ -0,0 +1,73 @@
import pytest
from unittest import mock
from django.core.mail.message import EmailMessage
import awx.main.notifications.slack_backend as slack_backend
def test_send_messages():
with mock.patch('awx.main.notifications.slack_backend.WebClient') as slack_sdk_mock:
WebClient_mock = slack_sdk_mock.return_value
WebClient_mock.chat_postMessage.return_value = {'ok': True}
backend = slack_backend.SlackBackend('slack_access_token')
message = EmailMessage(
'test subject',
'test body',
[],
[
'#random',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
WebClient_mock.chat_postMessage.assert_called_once_with(channel='random', as_user=True, text='test subject')
assert sent_messages == 1
def test_send_messages_with_color():
with mock.patch('awx.main.notifications.slack_backend.WebClient') as slack_sdk_mock:
WebClient_mock = slack_sdk_mock.return_value
WebClient_mock.chat_postMessage.return_value = {'ok': True}
backend = slack_backend.SlackBackend('slack_access_token', hex_color='#006699')
message = EmailMessage(
'test subject',
'test body',
[],
[
'#random',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
WebClient_mock.chat_postMessage.assert_called_once_with(channel='random', as_user=True, attachments=[{'color': '#006699', 'text': 'test subject'}])
assert sent_messages == 1
def test_send_messages_fail():
with mock.patch('awx.main.notifications.slack_backend.WebClient') as slack_sdk_mock, pytest.raises(RuntimeError, match=r'.*not_in_channel.*'):
WebClient_mock = slack_sdk_mock.return_value
WebClient_mock.chat_postMessage.return_value = {'ok': False, 'error': 'not_in_channel'}
backend = slack_backend.SlackBackend('slack_access_token')
message = EmailMessage(
'test subject',
'test body',
[],
[
'#not_existing',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
WebClient_mock.chat_postMessage.assert_called_once_with(channel='not_existing', as_user=True, text='test subject')
assert sent_messages == 0

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2016 Slack Technologies, Inc Copyright (c) 2015- Slack Technologies, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -108,12 +108,6 @@ Upgrading to 4.0.0 causes error because imports changed.
ImportError: cannot import name 'KeyVaultClient' ImportError: cannot import name 'KeyVaultClient'
``` ```
### slackclient
Imports as used in `awx/main/notifications/slack_backend.py` changed
in version 2.0. This plugin code will need to change and be re-tested
as the upgrade takes place.
### django-jsonfield ### django-jsonfield
Instead of calling a `loads()` operation, the returned value is casted into Instead of calling a `loads()` operation, the returned value is casted into

View File

@@ -50,7 +50,7 @@ social-auth-core==3.3.1 # see UPGRADE BLOCKERs
social-auth-app-django==3.1.0 # see UPGRADE BLOCKERs social-auth-app-django==3.1.0 # see UPGRADE BLOCKERs
redis redis
requests requests
slackclient==1.1.2 # see UPGRADE BLOCKERs slack-sdk
tacacs_plus==1.0 # UPGRADE BLOCKER: auth does not work with later versions tacacs_plus==1.0 # UPGRADE BLOCKER: auth does not work with later versions
twilio twilio
twisted[tls]>=20.3.0 # CVE-2020-10108, CVE-2020-10109 twisted[tls]>=20.3.0 # CVE-2020-10108, CVE-2020-10109

View File

@@ -320,7 +320,6 @@ requests==2.23.0
# python-dsv-sdk # python-dsv-sdk
# python-tss-sdk # python-tss-sdk
# requests-oauthlib # requests-oauthlib
# slackclient
# social-auth-core # social-auth-core
# twilio # twilio
requests-oauthlib==1.3.0 requests-oauthlib==1.3.0
@@ -358,13 +357,12 @@ six==1.14.0
# pyrad # pyrad
# pyrsistent # pyrsistent
# python-dateutil # python-dateutil
# slackclient
# social-auth-app-django # social-auth-app-django
# social-auth-core # social-auth-core
# tacacs-plus # tacacs-plus
# twilio # twilio
# websocket-client # websocket-client
slackclient==1.1.2 slack-sdk==3.11.2
# via -r /awx_devel/requirements/requirements.in # via -r /awx_devel/requirements/requirements.in
smmap==3.0.1 smmap==3.0.1
# via gitdb # via gitdb
@@ -399,9 +397,7 @@ uwsgi==2.0.18
uwsgitop==0.11 uwsgitop==0.11
# via -r /awx_devel/requirements/requirements.in # via -r /awx_devel/requirements/requirements.in
websocket-client==0.57.0 websocket-client==0.57.0
# via # via kubernetes
# kubernetes
# slackclient
wheel==0.36.2 wheel==0.36.2
# via -r /awx_devel/requirements/requirements.in # via -r /awx_devel/requirements/requirements.in
xmlsec==1.3.3 xmlsec==1.3.3