diff --git a/salt/states/slack.py b/salt/states/slack.py index f3545c795038..8eb0b823e33e 100644 --- a/salt/states/slack.py +++ b/salt/states/slack.py @@ -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. @@ -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: diff --git a/tests/unit/states/test_slack.py b/tests/unit/states/test_slack.py index 51b8fb99b390..0e87db2539ed 100644 --- a/tests/unit/states/test_slack.py +++ b/tests/unit/states/test_slack.py @@ -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': {}, @@ -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)