Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2019.2] Updating the slack state module to support webhooks #52715

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 78 additions & 36 deletions salt/states/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ def __virtual__():
return 'slack' if 'slack.post_message' in __salt__ else False


def post_message(name,
channel,
from_name,
message,
api_key=None,
icon=None):
def post_message(name, **kwargs):
'''
Send a message to a Slack channel.
Expand All @@ -59,57 +54,104 @@ def post_message(name,
The following parameters are required:
name
The unique name for this event.
api_key parameters:
name
The unique name for this event.
channel
The channel to send the message to. Can either be the ID or the name.
channel
The channel to send the message to. Can either be the ID or the name.
from_name
The name of that is to be shown in the "from" field.
from_name
The name of that is to be shown in the "from" field.
message
The message that is to be sent to the Slack channel.
message
The message that is to be sent to the Slack channel.
The following parameters are optional:
The following parameters are optional:
api_key
The api key for Slack to use for authentication,
if not specified in the configuration options of master or minion.
api_key
The api key for Slack to use for authentication,
if not specified in the configuration options of master or minion.
icon
URL to an image to use as the icon for this message
icon
URL to an image to use as the icon for this message
webhook parameters:
name
The unique name for this event.
message
The message that is to be sent to the Slack channel.
color
The color of border of left side
short
An optional flag indicating whether the value is short
enough to be displayed side-by-side with other values.
identifier
The identifier of WebHook.
channel
The channel to use instead of the WebHook default.
username
Username to use instead of WebHook default.
icon_emoji
Icon to use instead of WebHook default.
'''
ret = {'name': name,
'changes': {},
'result': False,
'comment': ''}

if __opts__['test']:
ret['comment'] = 'The following message is to be sent to Slack: {0}'.format(message)
ret['result'] = None
if not kwargs.get('api_key') and not kwargs.get('webhook'):
ret['comment'] = 'Please specify api_key or webhook.'
return ret

if kwargs.get('api_key') and kwargs.get('webhook'):
ret['comment'] = 'Please specify only either api_key or webhook.'
return ret

if not channel:
ret['comment'] = 'Slack channel is missing: {0}'.format(channel)
if kwargs.get('api_key') and not kwargs.get('channel'):
ret['comment'] = 'Slack channel is missing.'
return ret

if not from_name:
ret['comment'] = 'Slack from name is missing: {0}'.format(from_name)
if kwargs.get('api_key') and not kwargs.get('from_name'):
ret['comment'] = 'Slack from name is missing.'
return ret

if not message:
ret['comment'] = 'Slack message is missing: {0}'.format(message)
if not kwargs.get('message'):
ret['comment'] = 'Slack message is missing.'
return ret

if __opts__['test']:
ret['comment'] = 'The following message is to be sent to Slack: {0}'.format(kwargs.get('message'))
ret['result'] = None
return ret

try:
result = __salt__['slack.post_message'](
channel=channel,
message=message,
from_name=from_name,
api_key=api_key,
icon=icon,
)
if kwargs.get('api_key'):
result = __salt__['slack.post_message'](
channel=kwargs.get('channel'),
message=kwargs.get('message'),
from_name=kwargs.get('from_name'),
api_key=kwargs.get('api_key'),
icon=kwargs.get('icon'),
)
elif kwargs.get('webhook'):
result = __salt__['slack.call_hook'](
message=kwargs.get('message'),
attachment=kwargs.get('attachment'),
color=kwargs.get('color', 'good'),
short=kwargs.get('short'),
identifier=kwargs.get('webhook'),
channel=kwargs.get('channel'),
username=kwargs.get('username'),
icon_emoji=kwargs.get('icon_emoji')
)
except SaltInvocationError as sie:
ret['comment'] = 'Failed to send message ({0}): {1}'.format(sie, name)
else:
Expand Down
117 changes: 102 additions & 15 deletions tests/unit/states/test_slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ def setup_loader_modules(self):

# 'post_message' function tests: 1

def test_post_message(self):
def test_post_message_apikey(self):
'''
Test to send a message to a Slack channel.
Test to send a message to a Slack channel using an API Key.
'''
name = 'slack-message'
channel = '#general'
from_name = 'SuperAdmin'
message = 'This state was executed successfully.'
api_key = 'xoxp-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXXXX'

ret = {'name': name,
'changes': {},
Expand All @@ -47,29 +48,115 @@ def test_post_message(self):
comt = ('The following message is to be sent to Slack: {0}'
.format(message))
ret.update({'comment': comt})
self.assertDictEqual(slack.post_message(name, channel, from_name,
message), ret)
self.assertDictEqual(slack.post_message(name,
channel=channel,
from_name=from_name,
message=message,
api_key=api_key), ret)

with patch.dict(slack.__opts__, {'test': False}):
comt = ('Slack channel is missing: None')
comt = ('Please specify api_key or webhook.')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(slack.post_message(name, None, from_name,
message), ret)
self.assertDictEqual(slack.post_message(name,
channel=None,
from_name=from_name,
message=message,
api_key=None), ret)

comt = ('Slack from name is missing: None')
comt = ('Slack channel is missing.')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(slack.post_message(name, channel, None,
message), ret)
self.assertDictEqual(slack.post_message(name,
channel=None,
from_name=from_name,
message=message,
api_key=api_key), ret)

comt = ('Slack message is missing: None')
comt = ('Slack from name is missing.')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(slack.post_message(name, channel, from_name,
None), ret)
self.assertDictEqual(slack.post_message(name,
channel=channel,
from_name=None,
message=message,
api_key=api_key), ret)

comt = ('Slack message is missing.')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(slack.post_message(name,
channel=channel,
from_name=from_name,
message=None,
api_key=api_key), ret)

mock = MagicMock(return_value=True)
with patch.dict(slack.__salt__, {'slack.post_message': mock}):
comt = ('Sent message: slack-message')
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(slack.post_message(name, channel,
from_name, message),
self.assertDictEqual(slack.post_message(name,
channel=channel,
from_name=from_name,
message=message,
api_key=api_key),
ret)

def test_post_message_webhook(self):
'''
Test to send a message to a Slack channel using an webhook.
'''
name = 'slack-message'
channel = '#general'
username = 'SuperAdmin'
message = 'This state was executed successfully.'
webhook = 'XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX'
api_key = 'xoxp-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXXXX'

ret = {'name': name,
'changes': {},
'result': None,
'comment': ''}

with patch.dict(slack.__opts__, {'test': True}):
comt = ('The following message is to be sent to Slack: {0}'
.format(message))
ret.update({'comment': comt})
self.assertDictEqual(slack.post_message(name,
channel=channel,
username=username,
message=message,
webhook=webhook), ret)

with patch.dict(slack.__opts__, {'test': False}):
comt = ('Please specify api_key or webhook.')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(slack.post_message(name,
channel=channel,
username=username,
message=None,
webhook=None), ret)

comt = ('Please specify only either api_key or webhook.')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(slack.post_message(name,
channel=channel,
username=username,
message=message,
api_key=api_key,
webhook=webhook), ret)

comt = ('Slack message is missing.')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(slack.post_message(name,
channel=channel,
username=username,
message=None,
webhook=webhook), ret)

mock = MagicMock(return_value=True)
with patch.dict(slack.__salt__, {'slack.call_hook': mock}):
comt = ('Sent message: slack-message')
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(slack.post_message(name,
channel=channel,
username=username,
message=message,
webhook=webhook),
ret)