mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-06-27 18:50:21 -07:00
slack: support slack-gov.com (#10270)
Some checks are pending
EOL CI / EOL Sanity (Ⓐ2.16) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py2.7) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.11) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.6) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/3/) (push) Waiting to run
nox / Run extra sanity tests (push) Waiting to run
Some checks are pending
EOL CI / EOL Sanity (Ⓐ2.16) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py2.7) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.11) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.6) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/3/) (push) Waiting to run
nox / Run extra sanity tests (push) Waiting to run
* slack: support slack-gov.com Allow the slack module to work with GovSlack, hosted at https://slack-gov.com/ This re-uses the existing `domain` option so that users can set it to `slack-gov.com` to use GovSlack. To maintain backwards compatibility, any setting of `domain` for WebAPI tokens that is not `slack.com` or `slack-gov.com` is ignored. * fixup * cleanup * fix pep8 * clean up docs and better function name * document default value * try to fix yaml, not sure what is wrong * Update plugins/modules/slack.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/slack.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/slack.py Co-authored-by: Felix Fontein <felix@fontein.de> --------- Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
dd53a2cee0
commit
1ed0f329bc
2 changed files with 40 additions and 15 deletions
|
@ -32,8 +32,9 @@ options:
|
|||
domain:
|
||||
type: str
|
||||
description:
|
||||
- Slack (sub)domain for your environment without protocol. (For example V(example.slack.com).) In Ansible 1.8 and beyond,
|
||||
this is deprecated and may be ignored. See token documentation for information.
|
||||
- "When using new format 'Webhook token' and WebAPI tokens: this can be V(slack.com) or V(slack-gov.com) and is ignored otherwise."
|
||||
- "When using old format 'Webhook token': Slack (sub)domain for your environment without protocol. (For example V(example.slack.com).)
|
||||
in Ansible 1.8 and beyond, this is deprecated and may be ignored. See token documentation for information."
|
||||
token:
|
||||
type: str
|
||||
description:
|
||||
|
@ -41,9 +42,10 @@ options:
|
|||
depending on what method you use.
|
||||
- 'Webhook token: Prior to Ansible 1.8, a token looked like V(3Ffe373sfhRE6y42Fg3rvf4GlK). In Ansible 1.8 and above,
|
||||
Ansible adapts to the new slack API where tokens look like V(G922VJP24/D921DW937/3Ffe373sfhRE6y42Fg3rvf4GlK). If tokens
|
||||
are in the new format then slack will ignore any value of domain. If the token is in the old format the domain is
|
||||
required. Ansible has no control of when slack will get rid of the old API. When slack does that the old format will
|
||||
stop working. ** Please keep in mind the tokens are not the API tokens but are the webhook tokens. In slack these
|
||||
are in the new format then slack will ignore any value of domain except V(slack.com) or V(slack-gov.com). If the token
|
||||
is in the old format the domain is required. Ansible has no control of when slack will get rid of the old API. When slack
|
||||
does that the old format will stop working.
|
||||
** Please keep in mind the tokens are not the API tokens but are the webhook tokens. In slack these
|
||||
are found in the webhook URL which are obtained under the apps and integrations. The incoming webhooks can be added
|
||||
in that area. In some cases this may be locked by your Slack admin and you must request access. It is there that the
|
||||
incoming webhooks can be added. The key is on the end of the URL given to you in that section.'
|
||||
|
@ -267,10 +269,10 @@ from ansible.module_utils.six.moves.urllib.parse import urlencode
|
|||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
OLD_SLACK_INCOMING_WEBHOOK = 'https://%s/services/hooks/incoming-webhook?token=%s'
|
||||
SLACK_INCOMING_WEBHOOK = 'https://hooks.slack.com/services/%s'
|
||||
SLACK_POSTMESSAGE_WEBAPI = 'https://slack.com/api/chat.postMessage'
|
||||
SLACK_UPDATEMESSAGE_WEBAPI = 'https://slack.com/api/chat.update'
|
||||
SLACK_CONVERSATIONS_HISTORY_WEBAPI = 'https://slack.com/api/conversations.history'
|
||||
SLACK_INCOMING_WEBHOOK = 'https://hooks.%s/services/%s'
|
||||
SLACK_POSTMESSAGE_WEBAPI = 'https://%s/api/chat.postMessage'
|
||||
SLACK_UPDATEMESSAGE_WEBAPI = 'https://%s/api/chat.update'
|
||||
SLACK_CONVERSATIONS_HISTORY_WEBAPI = 'https://%s/api/conversations.history'
|
||||
|
||||
# Escaping quotes and apostrophes to avoid ending string prematurely in ansible call.
|
||||
# We do not escape other characters used as Slack metacharacters (e.g. &, <, >).
|
||||
|
@ -372,7 +374,11 @@ def build_payload_for_slack(text, channel, thread_id, username, icon_url, icon_e
|
|||
return payload
|
||||
|
||||
|
||||
def get_slack_message(module, token, channel, ts):
|
||||
def validate_slack_domain(domain):
|
||||
return (domain if domain in ('slack.com', 'slack-gov.com') else 'slack.com')
|
||||
|
||||
|
||||
def get_slack_message(module, domain, token, channel, ts):
|
||||
headers = {
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
'Accept': 'application/json',
|
||||
|
@ -384,7 +390,8 @@ def get_slack_message(module, token, channel, ts):
|
|||
'limit': 1,
|
||||
'inclusive': 'true',
|
||||
})
|
||||
url = SLACK_CONVERSATIONS_HISTORY_WEBAPI + '?' + qs
|
||||
domain = validate_slack_domain(domain)
|
||||
url = (SLACK_CONVERSATIONS_HISTORY_WEBAPI % domain) + '?' + qs
|
||||
response, info = fetch_url(module=module, url=url, headers=headers, method='GET')
|
||||
if info['status'] != 200:
|
||||
module.fail_json(msg="failed to get slack message")
|
||||
|
@ -402,9 +409,11 @@ def do_notify_slack(module, domain, token, payload):
|
|||
use_webapi = False
|
||||
if token.count('/') >= 2:
|
||||
# New style webhook token
|
||||
slack_uri = SLACK_INCOMING_WEBHOOK % token
|
||||
domain = validate_slack_domain(domain)
|
||||
slack_uri = SLACK_INCOMING_WEBHOOK % (domain, token)
|
||||
elif re.match(r'^xox[abp]-\S+$', token):
|
||||
slack_uri = SLACK_UPDATEMESSAGE_WEBAPI if 'ts' in payload else SLACK_POSTMESSAGE_WEBAPI
|
||||
domain = validate_slack_domain(domain)
|
||||
slack_uri = (SLACK_UPDATEMESSAGE_WEBAPI if 'ts' in payload else SLACK_POSTMESSAGE_WEBAPI) % domain
|
||||
use_webapi = True
|
||||
else:
|
||||
if not domain:
|
||||
|
@ -426,7 +435,7 @@ def do_notify_slack(module, domain, token, payload):
|
|||
if use_webapi:
|
||||
obscured_incoming_webhook = slack_uri
|
||||
else:
|
||||
obscured_incoming_webhook = SLACK_INCOMING_WEBHOOK % '[obscured]'
|
||||
obscured_incoming_webhook = SLACK_INCOMING_WEBHOOK % (domain, '[obscured]')
|
||||
module.fail_json(msg=" failed to send %s to %s: %s" % (data, obscured_incoming_webhook, info['msg']))
|
||||
|
||||
# each API requires different handling
|
||||
|
@ -494,7 +503,7 @@ def main():
|
|||
# if updating an existing message, we can check if there's anything to update
|
||||
if message_id is not None:
|
||||
changed = False
|
||||
msg = get_slack_message(module, token, channel, message_id)
|
||||
msg = get_slack_message(module, domain, token, channel, message_id)
|
||||
for key in ('icon_url', 'icon_emoji', 'link_names', 'color', 'attachments', 'blocks'):
|
||||
if msg.get(key) != module.params.get(key):
|
||||
changed = True
|
||||
|
|
|
@ -103,6 +103,22 @@ class TestSlackModule(ModuleTestCase):
|
|||
self.assertTrue(fetch_url_mock.call_count, 1)
|
||||
self.assertEqual(fetch_url_mock.call_args[1]['url'], "https://slack.com/api/chat.postMessage")
|
||||
|
||||
def test_govslack_message(self):
|
||||
with set_module_args({
|
||||
'token': 'xoxa-123456789abcdef',
|
||||
'domain': 'slack-gov.com',
|
||||
'msg': 'test with ts'
|
||||
}):
|
||||
with patch.object(slack, "fetch_url") as fetch_url_mock:
|
||||
mock_response = Mock()
|
||||
mock_response.read.return_value = '{"fake":"data"}'
|
||||
fetch_url_mock.return_value = (mock_response, {"status": 200})
|
||||
with self.assertRaises(AnsibleExitJson):
|
||||
self.module.main()
|
||||
|
||||
self.assertTrue(fetch_url_mock.call_count, 1)
|
||||
self.assertEqual(fetch_url_mock.call_args[1]['url'], "https://slack-gov.com/api/chat.postMessage")
|
||||
|
||||
def test_edit_message(self):
|
||||
with set_module_args({
|
||||
'token': 'xoxa-123456789abcdef',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue